smugmugapi 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +18 -0
- data/README.txt +61 -0
- data/Rakefile +15 -0
- data/examples/upload.rb +19 -0
- data/lib/smugmug/core.rb +88 -0
- data/lib/smugmug/exception.rb +4 -0
- data/lib/smugmug/logon.rb +49 -0
- data/lib/smugmug/proxy.rb +37 -0
- data/lib/smugmug/upload.rb +29 -0
- data/lib/smugmug/utility.rb +15 -0
- data/lib/smugmug/xmlstruct.rb +88 -0
- data/lib/smugmugapi.rb +33 -0
- data/test/test_smugmug.rb +10 -0
- data/test/test_utility.rb +22 -0
- data/test/test_xmlstruct.rb +44 -0
- data.tar.gz.sig +2 -0
- metadata +96 -0
- metadata.gz.sig +0 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
lib/smugmugapi.rb
|
6
|
+
lib/smugmug/core.rb
|
7
|
+
lib/smugmug/exception.rb
|
8
|
+
lib/smugmug/logon.rb
|
9
|
+
lib/smugmug/proxy.rb
|
10
|
+
lib/smugmug/upload.rb
|
11
|
+
lib/smugmug/utility.rb
|
12
|
+
lib/smugmug/xmlstruct.rb
|
13
|
+
examples/upload.rb
|
14
|
+
test/test_smugmug.rb
|
15
|
+
test/test_smugmug.rb
|
16
|
+
test/test_smugmug.rb
|
17
|
+
test/test_utility.rb
|
18
|
+
test/test_xmlstruct.rb
|
data/README.txt
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
smugmug
|
2
|
+
by Patrick Hurley
|
3
|
+
http://rubygorge.org/projects/sumgmugapi/
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
A very light wrapper around the 1.2.0 and 1.2.1 REST API at SmugMug
|
8
|
+
(http://smugmug.com/). The syntax is almost identical to the one
|
9
|
+
described at the wiki (http://smugmug.jot.com/WikiHome/1.2.0).
|
10
|
+
|
11
|
+
== FEATURES/PROBLEMS:
|
12
|
+
|
13
|
+
I have written some simple tests of my "local" code, but have not
|
14
|
+
attempted to mock out SmugMug or write a bunch of fragile hard coded
|
15
|
+
tests.
|
16
|
+
|
17
|
+
On top of that I just put the code together without tests as I was
|
18
|
+
"testing" against the API. So there are a few more rough edges than
|
19
|
+
I like, but it does seem to work :-)
|
20
|
+
|
21
|
+
So I know there will be bugs, sorry -- please let me know when you
|
22
|
+
find them and I will try and fix them as quickly as possible.
|
23
|
+
|
24
|
+
== SYNOPSIS:
|
25
|
+
|
26
|
+
See examples sub-directory, have a question (or a good example),
|
27
|
+
please drop me an email and I will add it to the examples directory,
|
28
|
+
at least till we get real documentation (don't hold your breath :-)
|
29
|
+
|
30
|
+
== REQUIREMENTS:
|
31
|
+
|
32
|
+
Internet tubes
|
33
|
+
|
34
|
+
== INSTALL:
|
35
|
+
|
36
|
+
sudo gem install smugmugapi
|
37
|
+
|
38
|
+
== LICENSE:
|
39
|
+
|
40
|
+
(The MIT License)
|
41
|
+
|
42
|
+
Copyright (c) 2007 Patrick Hurley
|
43
|
+
|
44
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
45
|
+
a copy of this software and associated documentation files (the
|
46
|
+
'Software'), to deal in the Software without restriction, including
|
47
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
48
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
49
|
+
permit persons to whom the Software is furnished to do so, subject to
|
50
|
+
the following conditions:
|
51
|
+
|
52
|
+
The above copyright notice and this permission notice shall be
|
53
|
+
included in all copies or substantial portions of the Software.
|
54
|
+
|
55
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
56
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
57
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
58
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
59
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
60
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
61
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/smugmugapi.rb'
|
6
|
+
|
7
|
+
Hoe.new('smugmugapi', SmugMugAPI::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'smugmugapi'
|
9
|
+
p.author = 'Patrick Hurley'
|
10
|
+
p.email = 'phurley@gmail.com'
|
11
|
+
p.summary = 'A very light wrapper around the SmugMug REST API'
|
12
|
+
p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
|
13
|
+
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
14
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
15
|
+
end
|
data/examples/upload.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "smugmugapi"
|
3
|
+
|
4
|
+
# And you thought I would put my password here for you :-)
|
5
|
+
smugmug.login("phurley@gmail.com", IO.read('password')) do
|
6
|
+
|
7
|
+
category = smugmug.categories.get.find { |e| e.title.match(/family/i) }.id
|
8
|
+
|
9
|
+
album = smugmug.albums.create(
|
10
|
+
:title => 'Test Album',
|
11
|
+
:category_id => category,
|
12
|
+
:description => 'Just made this album',
|
13
|
+
:keywords => 'blue apple foo bar'
|
14
|
+
)
|
15
|
+
album = album.id
|
16
|
+
|
17
|
+
puts smugmug.upload('mona_lisa.jpg', :album_id => album, :caption => "Wow it actually works")
|
18
|
+
|
19
|
+
end
|
data/lib/smugmug/core.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require "rexml/document"
|
2
|
+
require "uri"
|
3
|
+
require "net/https"
|
4
|
+
|
5
|
+
class SmugMugAPI
|
6
|
+
class << self
|
7
|
+
USERAGENT = "SumMug Ruby API Library"
|
8
|
+
|
9
|
+
attr_writer :api_key, :agent, :api_version, :default_params
|
10
|
+
|
11
|
+
def default_params
|
12
|
+
@default_params ||= { :APIKey => api_key }
|
13
|
+
end
|
14
|
+
|
15
|
+
def api_version
|
16
|
+
@api_version || '1.2.0'
|
17
|
+
end
|
18
|
+
|
19
|
+
def api_key
|
20
|
+
@api_key || 'RXcw7ywveg9pEj1n6HBJfuDXqsFsx4jw'
|
21
|
+
end
|
22
|
+
|
23
|
+
def api_path
|
24
|
+
@url || "api.smugmug.com/hack/rest/#{api_version}/"
|
25
|
+
end
|
26
|
+
|
27
|
+
def agent
|
28
|
+
@agent || USERAGENT
|
29
|
+
end
|
30
|
+
|
31
|
+
def groups
|
32
|
+
# it would be better to have a smugmug reflection method to
|
33
|
+
# get this information but this is a fairly exhaustive list
|
34
|
+
# and it will be easy to add to this as well
|
35
|
+
%w(albums albumtemplates categories images login subcategories users
|
36
|
+
|
37
|
+
communities family friends orders pricing propricing sharegroups
|
38
|
+
styles themes watermarks)
|
39
|
+
end
|
40
|
+
|
41
|
+
def get(passed_params, headers={}, transport='http')
|
42
|
+
params = default_params.merge(passed_params)
|
43
|
+
|
44
|
+
url = transport + "://" + api_path + "?" +
|
45
|
+
params.map { |k,v| URI.encode("#{SmugMugAPI.camelize(k)}=#{v}") }.join("&")
|
46
|
+
uri = URI.parse(url)
|
47
|
+
headers['User-Agent'] = agent
|
48
|
+
|
49
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
50
|
+
if transport == 'https'
|
51
|
+
http.use_ssl = true
|
52
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
53
|
+
end
|
54
|
+
|
55
|
+
http.start do
|
56
|
+
http.get(uri.path + '?' + uri.query, headers)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_response(response)
|
61
|
+
puts "HTTP #{response.code}: #{response.message}" if $DEBUG
|
62
|
+
|
63
|
+
raise SmugMugAPI::Error.new("HTTP #{response.code} on #{url}") unless response.code.to_i == 200
|
64
|
+
|
65
|
+
doc = REXML::Document.new(response.body)
|
66
|
+
if doc.root.attributes['stat'] != 'ok'
|
67
|
+
err = doc.root.elements['/rsp/err']
|
68
|
+
code = err.attributes['code']
|
69
|
+
msg = err.attributes['msg']
|
70
|
+
raise SmugMugAPI::Error.new("#{code}: #{msg}")
|
71
|
+
end
|
72
|
+
|
73
|
+
XMLStruct.new(doc)
|
74
|
+
end
|
75
|
+
|
76
|
+
def https_call(params={})
|
77
|
+
call(params, 'https')
|
78
|
+
end
|
79
|
+
|
80
|
+
def http_call(params={})
|
81
|
+
call(params, 'http')
|
82
|
+
end
|
83
|
+
|
84
|
+
def call(params={}, transport = "http")
|
85
|
+
parse_response(get(params, {}, transport))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class SmugMugAPI
|
2
|
+
|
3
|
+
def login(email, password)
|
4
|
+
res = SmugMugAPI.https_call(
|
5
|
+
:method => 'smugmug.login.withPassword',
|
6
|
+
:EmailAddress => email,
|
7
|
+
:Password => password
|
8
|
+
)
|
9
|
+
|
10
|
+
SmugMugAPI.default_params[:SessionID] = res.session.id
|
11
|
+
|
12
|
+
if block_given?
|
13
|
+
begin
|
14
|
+
yield res
|
15
|
+
ensure
|
16
|
+
logout
|
17
|
+
end
|
18
|
+
else
|
19
|
+
res
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def login_with_hash(user, hash)
|
24
|
+
res = SmugMugAPI.https_call(
|
25
|
+
:method => 'smugmug.login.withHash',
|
26
|
+
:UserID => user,
|
27
|
+
:PasswordHash => hash
|
28
|
+
)
|
29
|
+
|
30
|
+
SmugMugAPI.default_params[:SessionID] = res.session.id
|
31
|
+
|
32
|
+
if block_given?
|
33
|
+
begin
|
34
|
+
yield res
|
35
|
+
ensure
|
36
|
+
logout
|
37
|
+
end
|
38
|
+
else
|
39
|
+
res
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def logout
|
44
|
+
result = SmugMugAPI.call(:method => 'smugmug.logout')
|
45
|
+
SmugMugAPI.default_params.delete(:SessionID)
|
46
|
+
result
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "xmlstruct"
|
2
|
+
|
3
|
+
class SmugProxy
|
4
|
+
def initialize(base="", params = {})
|
5
|
+
@base = base
|
6
|
+
@params = params
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing(method, params={})
|
10
|
+
method = method.to_s.gsub(/_(.)/) { $1.upcase }
|
11
|
+
method = method.gsub(/URL/i, "URL").gsub(/EXIF/i, "EXIF")
|
12
|
+
|
13
|
+
# it would be better to have a smugmug reflection method to get this information
|
14
|
+
# but this is a fairly exhaustive list and it will be easy to add to this as well
|
15
|
+
groups = %w(albums albumtemplates categories images login subcategories users
|
16
|
+
communities family friends orders pricing propricing sharegroups styles themes watermarks)
|
17
|
+
|
18
|
+
if groups.include?(method)
|
19
|
+
SmugProxy.new(@base + "." + method.to_s, params)
|
20
|
+
else
|
21
|
+
puts "CALL: #{@base + "." + method}(#{params.inspect})"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
@base + "(#{@params.inspect})"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
sm = SmugProxy.new("smugmug")
|
31
|
+
puts sm
|
32
|
+
|
33
|
+
sm.users.get_tree("wow")
|
34
|
+
sm.users.getTree("wow")
|
35
|
+
sm.images.images.family.getURLs
|
36
|
+
sm.images.get_urls
|
37
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require "pp"
|
3
|
+
|
4
|
+
class SmugMugAPI
|
5
|
+
|
6
|
+
def upload(fname, params={})
|
7
|
+
base_name = File.basename(fname)
|
8
|
+
uri = URI.parse("http://upload.smugmug.com/#{base_name}")
|
9
|
+
image = IO::read(fname)
|
10
|
+
|
11
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
12
|
+
headers = {
|
13
|
+
'Content-Type' => 'image/jpeg',
|
14
|
+
'Content-Lenth' => image.size.to_s,
|
15
|
+
'Content-MD5' => Digest::MD5.hexdigest(image),
|
16
|
+
'X-Smug-SessionID' => SmugMugAPI.default_params[:SessionID],
|
17
|
+
'X-Smug-Version' => SmugMugAPI.api_version,
|
18
|
+
'X-Smug-ResponseType' => 'REST',
|
19
|
+
'X-Smug-FileName' => base_name
|
20
|
+
}
|
21
|
+
|
22
|
+
adjusted_headers = Hash[*params.map { |k,v| [ "X-Smug-" + SmugMugAPI.camelize(k), v.to_s ] }.flatten ]
|
23
|
+
headers = headers.merge(adjusted_headers)
|
24
|
+
|
25
|
+
resp = http.send_request('PUT', uri.request_uri, image, headers)
|
26
|
+
SmugMugAPI.parse_response(resp)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class SmugMugAPI
|
2
|
+
def self.camelize(str, upcase_first_char = true)
|
3
|
+
if upcase_first_char
|
4
|
+
str = str.to_s.gsub(/(^|_)(.)/) { $2.upcase }
|
5
|
+
else
|
6
|
+
str = str.to_s.gsub(/_(.)/) { $1.upcase }
|
7
|
+
end
|
8
|
+
str = str.gsub(/URL/i, "URL").gsub(/EXIF/i, "EXIF")
|
9
|
+
str = str.gsub(/(?!^)ID$/i, "ID")
|
10
|
+
str = str.gsub(/EXIF/i, "EXIF")
|
11
|
+
str = str.gsub(/X(.?)Large/i) { "X#{$1}Large" }
|
12
|
+
str = "method" if str == "Method" #special case
|
13
|
+
str
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
|
2
|
+
class SmugMugAPI
|
3
|
+
class XMLStruct
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def id(*args)
|
7
|
+
method_missing(:id, *args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(xml)
|
11
|
+
if xml.is_a?(REXML::Document)
|
12
|
+
@xml = xml.root.elements[2]
|
13
|
+
else
|
14
|
+
@xml = xml
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.attrib_key(key)
|
19
|
+
case key
|
20
|
+
when "Id", "id", :id
|
21
|
+
"id"
|
22
|
+
when Fixnum
|
23
|
+
key
|
24
|
+
else
|
25
|
+
key = XMLStruct.camalize(key)
|
26
|
+
key = key.gsub(/ID$/i, "ID")
|
27
|
+
key = key.gsub(/EXIF/i, "EXIF")
|
28
|
+
key.gsub(/X(.?)Large/i) { "X#{$1}Large" }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def [](attrib)
|
33
|
+
if attrib.is_a?(Fixnum)
|
34
|
+
# puts "Finding #{attrib} hmmm: #{@xml.elements[attrib]}"
|
35
|
+
result = XMLStruct.new(@xml.elements[attrib])
|
36
|
+
# puts "Found #{result}"
|
37
|
+
result
|
38
|
+
else
|
39
|
+
# key = XMLStruct.attrib_key(attrib)
|
40
|
+
@xml.attributes[XMLStruct.attrib_key(attrib)]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def first
|
45
|
+
XMLStruct.new(@xml.elements[1])
|
46
|
+
end
|
47
|
+
|
48
|
+
def size
|
49
|
+
@xml.elements.size
|
50
|
+
end
|
51
|
+
|
52
|
+
def empty?
|
53
|
+
size == 0
|
54
|
+
end
|
55
|
+
|
56
|
+
def last
|
57
|
+
XMLStruct.new(@xml.elements[@xml.elements.size])
|
58
|
+
end
|
59
|
+
|
60
|
+
def []=(attrib,value)
|
61
|
+
@xml.attributes[XMLStruct.attrib_key(attrib)] = value
|
62
|
+
end
|
63
|
+
|
64
|
+
def each
|
65
|
+
@xml.elements.each do |xml|
|
66
|
+
yield XMLStruct.new(xml)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def method_missing(*args)
|
71
|
+
method = XMLStruct.camalize(args.shift)
|
72
|
+
path = "#{method}"
|
73
|
+
if node = @xml.elements[path]
|
74
|
+
XMLStruct.new(node)
|
75
|
+
else
|
76
|
+
self[method]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.camalize(str)
|
81
|
+
str.to_s.gsub(/(^|_)(.)/) { $2.upcase }
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_s
|
85
|
+
@xml.to_s
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/smugmugapi.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "smugmug/core")
|
2
|
+
require File.join(File.dirname(__FILE__), "smugmug/utility")
|
3
|
+
require File.join(File.dirname(__FILE__), "smugmug/xmlstruct")
|
4
|
+
require File.join(File.dirname(__FILE__), "smugmug/exception")
|
5
|
+
require File.join(File.dirname(__FILE__), "smugmug/upload")
|
6
|
+
require File.join(File.dirname(__FILE__), "smugmug/logon")
|
7
|
+
|
8
|
+
class SmugMugAPI
|
9
|
+
VERSION = "0.9.0"
|
10
|
+
|
11
|
+
def initialize(base="smugmug")
|
12
|
+
@base = base
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(method, *params)
|
16
|
+
cmd = @base + "." + SmugMugAPI.camelize(method, false)
|
17
|
+
if SmugMugAPI.groups.include?(method.to_s)
|
18
|
+
SmugMugAPI.new(cmd)
|
19
|
+
else
|
20
|
+
param_hash = params.first || {}
|
21
|
+
SmugMugAPI.call(
|
22
|
+
{ :method => cmd }.merge(param_hash)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# added here for pretty interface
|
29
|
+
module Kernel
|
30
|
+
def smugmug(*params)
|
31
|
+
@smugmug ||= SmugMugAPI.new
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
require "smugmugapi"
|
4
|
+
|
5
|
+
class TestUtility < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_camelize_specials
|
8
|
+
# special cases, used to smooth out the meta madness
|
9
|
+
test_data = [
|
10
|
+
["PhotoID", "photo_id"],
|
11
|
+
["PhotoEXIF", "photo_exif"],
|
12
|
+
["PhotoURL", "photo_url"],
|
13
|
+
["X3Large", "x3_large"],
|
14
|
+
["X3Large", "x3large"],
|
15
|
+
["method", "method"],
|
16
|
+
]
|
17
|
+
|
18
|
+
test_data.each do |expected, raw|
|
19
|
+
assert_equal(expected, SmugMugAPI.camelize(raw))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
require "smugmugapi"
|
4
|
+
|
5
|
+
class TestXMLStruct < Test::Unit::TestCase
|
6
|
+
ALBUM = <<EOF
|
7
|
+
<?xml version='1.0' encoding='UTF-8'?>
|
8
|
+
<rsp stat='ok'>
|
9
|
+
<method>smugmug.albums.get</method>
|
10
|
+
<Albums>
|
11
|
+
<Album id='3903818' Title='Decorating for xmas 2007' Passworded='0' ImageCount='7'>
|
12
|
+
<Category Name='Holidays' id='31'/>
|
13
|
+
</Album>
|
14
|
+
<Album id='3903815' Title='Misc Fall 2007' Passworded='0' ImageCount='11'>
|
15
|
+
<Category Name='Other' id='0'/>
|
16
|
+
</Album>
|
17
|
+
<Album id='3903813' Title='Pat's 40th Birthday' Passworded='0' ImageCount='23'>
|
18
|
+
<Category Name='Other' id='0'/>
|
19
|
+
</Album>
|
20
|
+
<Album id='3903805' Title='Hurleyhome' Passworded='0' ImageCount='0'>
|
21
|
+
<Category Name='Family' id='9'/>
|
22
|
+
</Album>
|
23
|
+
</Albums>
|
24
|
+
</rsp>
|
25
|
+
EOF
|
26
|
+
|
27
|
+
def test_album_queries
|
28
|
+
albums = SmugMugAPI::XMLStruct.new(REXML::Document.new(ALBUM))
|
29
|
+
|
30
|
+
assert_equal(4, albums.size)
|
31
|
+
assert_equal(31, albums[1].category.id.to_i)
|
32
|
+
assert_equal('Holidays', albums[1].category.name)
|
33
|
+
assert_equal('Other', albums[2].category.name)
|
34
|
+
assert_equal('Family', albums.last.category.name)
|
35
|
+
|
36
|
+
assert_equal("Holidays", albums.first.category.name)
|
37
|
+
assert_equal("Decorating for xmas 2007", albums.first.title)
|
38
|
+
|
39
|
+
assert_equal("Pat's 40th Birthday", albums[3].title)
|
40
|
+
end
|
41
|
+
|
42
|
+
# need many more tests for my meta maddness
|
43
|
+
# feel free to write lots of tests :-)
|
44
|
+
end
|
data.tar.gz.sig
ADDED
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.4
|
3
|
+
specification_version: 1
|
4
|
+
name: smugmugapi
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.9.0
|
7
|
+
date: 2007-12-03 00:00:00 -05:00
|
8
|
+
summary: A very light wrapper around the SmugMug REST API
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: phurley@gmail.com
|
12
|
+
homepage: " by Patrick Hurley"
|
13
|
+
rubyforge_project: smugmugapi
|
14
|
+
description: "== FEATURES/PROBLEMS: I have written some simple tests of my \"local\" code, but have not attempted to mock out SmugMug or write a bunch of fragile hard coded tests. On top of that I just put the code together without tests as I was \"testing\" against the API. So there are a few more rough edges than I like, but it does seem to work :-) So I know there will be bugs, sorry -- please let me know when you find them and I will try and fix them as quickly as possible. == SYNOPSIS:"
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
- |
|
29
|
+
-----BEGIN CERTIFICATE-----
|
30
|
+
MIIDMDCCAhigAwIBAgIBADANBgkqhkiG9w0BAQUFADA+MRAwDgYDVQQDDAdwaHVy
|
31
|
+
bGV5MRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNjb20w
|
32
|
+
HhcNMDcxMjAzMjAyNjU5WhcNMDgxMjAyMjAyNjU5WjA+MRAwDgYDVQQDDAdwaHVy
|
33
|
+
bGV5MRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNjb20w
|
34
|
+
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC00L0dHlSg1NL6oIUrcRBs
|
35
|
+
pU9MtYdRjYTqR+tERyl5Wk8UNIFuzIQNpeMrzg2NOe4O6xxycr8wzZ4w64LYxrtd
|
36
|
+
uzII7tJOJd5HchVGi31EDPpc+oHSeNPkOtOjIWkpkfdHSuyqpQcyvXb6sdmF9LGU
|
37
|
+
vZGoPdesijBE5hzQvZ2IOeXKZh+i5I4/HoXbd7vS6h5mxTDM3LUATxt7AdHgmq7R
|
38
|
+
8XSib1pDniYAx5jPOc++aN3pGkCXragDa48CssEHMCgTE8hsYTOPNeN8BMCkit/r
|
39
|
+
py7uigHQ3ZCMc9g77WAHuJ5BR2kpZgdy/GQd9NgAGhJqr2Agd3ksGeGL2cgHDat9
|
40
|
+
AgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBSP1Olh
|
41
|
+
sOUBB6iyLHQFmbbUttDd9jANBgkqhkiG9w0BAQUFAAOCAQEAj6jHhZBNrhzYIUrv
|
42
|
+
DUUQ++8/9jCO2+NjBQC7O3Vme0bloMJtErIw4kHYICBaAbpk26Csx+0As4vquDmo
|
43
|
+
LJwA/nXRbJSB3rj9kAU4nWaWQhIyrm0R+Vt5WENNeo4FoBaZvkb/ghE0Ywni1aLq
|
44
|
+
9fvn84MwVZzQenvY1drn9jARZH+eq/NDOUloFlndccrYeBgoZJKi81xYuzwgjzU0
|
45
|
+
+aeEWr1e/UCRL8/zg7K6ywuEbeCTszJfK0pWSbFkMMm+ZRgvgsKx3E3C0KZUUz/1
|
46
|
+
alHFBzBR9j68NPrORviWlClOXtvA16AyJPfIb/tJiSN11RZC2lyVwIdK3/1L/ckA
|
47
|
+
9WgvxA==
|
48
|
+
-----END CERTIFICATE-----
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
authors:
|
52
|
+
- Patrick Hurley
|
53
|
+
files:
|
54
|
+
- History.txt
|
55
|
+
- Manifest.txt
|
56
|
+
- README.txt
|
57
|
+
- Rakefile
|
58
|
+
- lib/smugmugapi.rb
|
59
|
+
- lib/smugmug/core.rb
|
60
|
+
- lib/smugmug/exception.rb
|
61
|
+
- lib/smugmug/logon.rb
|
62
|
+
- lib/smugmug/proxy.rb
|
63
|
+
- lib/smugmug/upload.rb
|
64
|
+
- lib/smugmug/utility.rb
|
65
|
+
- lib/smugmug/xmlstruct.rb
|
66
|
+
- examples/upload.rb
|
67
|
+
- test/test_smugmug.rb
|
68
|
+
- test/test_utility.rb
|
69
|
+
- test/test_xmlstruct.rb
|
70
|
+
test_files:
|
71
|
+
- test/test_smugmug.rb
|
72
|
+
- test/test_utility.rb
|
73
|
+
- test/test_xmlstruct.rb
|
74
|
+
rdoc_options:
|
75
|
+
- --main
|
76
|
+
- README.txt
|
77
|
+
extra_rdoc_files:
|
78
|
+
- History.txt
|
79
|
+
- Manifest.txt
|
80
|
+
- README.txt
|
81
|
+
executables: []
|
82
|
+
|
83
|
+
extensions: []
|
84
|
+
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
dependencies:
|
88
|
+
- !ruby/object:Gem::Dependency
|
89
|
+
name: hoe
|
90
|
+
version_requirement:
|
91
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 1.3.0
|
96
|
+
version:
|
metadata.gz.sig
ADDED
Binary file
|