davetron5000-gliffy 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,127 @@
1
+ require 'rexml/document'
2
+ require 'array_has_response'
3
+ require 'gliffy/rest'
4
+
5
+ include REXML
6
+
7
+ module Gliffy
8
+
9
+ # Base class for Gliffy response. This class is also the entry point
10
+ # for parsing Gliffy XML:
11
+ #
12
+ # xml = get_xml_from_gliffy
13
+ # response = self.from_xml(xml)
14
+ # # response is now a Response or subclass of response
15
+ # if response.success?
16
+ # if response.not_modified?
17
+ # # use the item(s) from your local cache
18
+ # else
19
+ # # it should be what you expect, e.g. Diagram, array of Users, etc.
20
+ # end
21
+ # else
22
+ # puts response.message # in this case it's an Error
23
+ # end
24
+ #
25
+ #
26
+ class Response
27
+
28
+ # Creates a Response based on the XML passed in.
29
+ # The xml can be anything passable to REXML::Document.new, such as
30
+ # a Document, or a string containing XML
31
+ #
32
+ # This will return a Response, a subclass of Response, or an array of
33
+ # Response/subclass of Response objects. In the case where an array is returned
34
+ # both success? and not_modified? may be called, so the idiom in the class Rdoc should
35
+ # be usable regardless of return value
36
+ def self.from_xml(xml)
37
+ raise ArgumentError.new("xml may not be null to #{to_s}.from_xml") if !xml
38
+ root = Document.new(xml).root
39
+ not_modified = root.attributes['not-modified'] == "true"
40
+ success = root.attributes['success'] == "true"
41
+
42
+ response = nil
43
+ if ! root.elements.empty?
44
+ klassname = to_classname(root.elements[1].name)
45
+ klass = Gliffy.const_get(klassname)
46
+ response = klass.from_xml(root.elements[1])
47
+ else
48
+ response = Response.new
49
+ end
50
+
51
+ response.success = success
52
+ response.not_modified = not_modified
53
+
54
+ response
55
+ end
56
+
57
+ # Returns true if the response represents a successful response
58
+ # false indicates failure and that element is most likely a Error
59
+ def success?; @success; end
60
+
61
+ # Returns true if this response indicates the requested resource
62
+ # was not modified, based on the headers provided with the request.
63
+ def not_modified?; @not_modified; end
64
+
65
+ def success=(s); @success = s; end
66
+ def not_modified=(s); @not_modified = s; end
67
+
68
+ # Provides access to the rest implementation
69
+ attr_accessor :rest
70
+
71
+ protected
72
+
73
+ def initialize
74
+ @success = true
75
+ @not_modified = false
76
+ end
77
+
78
+ # Converts a dash-delimited string to a camel-cased classname
79
+ def self.to_classname(name)
80
+ classname = ""
81
+ name.split(/-/).each do |part|
82
+ classname += part.capitalize
83
+ end
84
+ classname
85
+ end
86
+ end
87
+
88
+ class ArrayResponseParser
89
+ def self.from_xml(element)
90
+ single_classname = self.to_s.gsub(/s$/,'').gsub(/Gliffy::/,'')
91
+ klass = Gliffy.const_get(single_classname)
92
+ list = Array.new
93
+ if (element)
94
+ element.each_element do |element|
95
+ list << klass.from_xml(element)
96
+ end
97
+ end
98
+ list
99
+ end
100
+ end
101
+
102
+ # An error from Gliffy
103
+ class Error < Response
104
+ # The HTTP status code that can help indicate the nature of the problem
105
+ attr_reader :http_status
106
+ # A description of the error that occured; not necessarily for human
107
+ # consumption
108
+ attr_reader :message
109
+
110
+ def self.from_xml(element)
111
+ message = element.text
112
+ http_status = element.attributes['http-status'].to_i
113
+ Error.new(message,http_status)
114
+ end
115
+
116
+ def initialize(message,http_status)
117
+ super()
118
+ @message = message
119
+ @http_status = http_status
120
+ end
121
+
122
+ def to_s
123
+ "#{@http_status}: #{@message}"
124
+ end
125
+
126
+ end
127
+ end
@@ -0,0 +1,110 @@
1
+ require 'digest/md5'
2
+ require 'cgi'
3
+ require 'rubygems'
4
+ require 'request_errors'
5
+ require 'resource'
6
+ require 'rest_client'
7
+
8
+ require 'gliffy/config'
9
+ require 'gliffy/url'
10
+
11
+ require 'logger'
12
+
13
+ module Gliffy
14
+
15
+ # Provides REST access to Gliffy, handling the signing of the requests
16
+ # but not the parsing of the results. This class responds to the four primary HTTP methods:
17
+ #
18
+ # * get
19
+ # * put
20
+ # * post
21
+ # * delete
22
+ #
23
+ # Each method takes three parameters:
24
+ # [url] - the relative URL being requested
25
+ # [params] - a hash of parameters to include in the request (these are specific to the request, not things like apiKey or token)
26
+ # [headers] - any HTTP headers you want to set
27
+ #
28
+ # params and headers are optional. These methods return whatever Gliffy sent back. The context
29
+ # of the request should be used to determine the type, however it should be relatively safe to call
30
+ # Response#success? on whatever is returned to determine if everythign was OK
31
+ #
32
+ class Rest
33
+
34
+ # Provides access to the current token,
35
+ # returning nil if none has been set
36
+ attr_accessor :current_token
37
+
38
+ # Provides access to the logger
39
+ # Do not set this to nil
40
+ attr_accessor :logger
41
+
42
+ attr_accessor :rest_client
43
+
44
+ # Create an accessor to the Gliffy REST api
45
+ #
46
+ def initialize
47
+ @current_token = nil
48
+ self.rest_client=RestClient
49
+ @logger = Logger.new(Config.config.log_device)
50
+ @logger.level = Config.config.log_level
51
+
52
+ @logger.debug("Creating #{self.class.to_s} with api_key of #{Config.config.api_key} against #{Config.config.gliffy_root}")
53
+ end
54
+
55
+ # Returns the complete URL that would be requested for
56
+ # the given URL and parameters
57
+ #
58
+ # [url] the URL, relative to the Gliffy API Root
59
+ # [params] a hash of parameters
60
+ #
61
+ def get_url(url,params=nil)
62
+ return create_url(url,params)
63
+ end
64
+
65
+ # Implements the http methods
66
+ def method_missing(symbol,*args)
67
+ if HTTP_METHODS[symbol] && (args.length > 0)
68
+ url,params,headers = args
69
+ make_rest_request(symbol,url,params,headers)
70
+ else
71
+ if (HTTP_METHODS[symbol])
72
+ raise ArgumentError.new("Wrong number of arguments for method #{symbol.to_s}")
73
+ else
74
+ super.method_missing(symbol,*args)
75
+ end
76
+ end
77
+ end
78
+
79
+ # Create the URL that would be needed to access the given resource with the given
80
+ # parameters
81
+ #
82
+ # [+url+] url, relative to the gliffy root, to retrieve
83
+ # [+params+] optional hash of parameters
84
+ #
85
+ def create_url(url,params=nil)
86
+ url = SignedURL.new(Config.config.api_key,Config.config.secret_key,Config.config.gliffy_root,url)
87
+ url.params=params if params
88
+ url['token'] = @current_token.token if @current_token
89
+
90
+ url.full_url
91
+ end
92
+
93
+ protected
94
+
95
+ def make_rest_request(method,url,params,headers)
96
+ headers = Hash.new if !headers
97
+ request_url = create_url(url,params)
98
+ @logger.debug("#{method.to_s.upcase} #{request_url}")
99
+ @rest_client.send(method,request_url,headers)
100
+ end
101
+
102
+ HTTP_METHODS = {
103
+ :get => true,
104
+ :put => true,
105
+ :delete => true,
106
+ :post => true,
107
+ };
108
+
109
+ end
110
+ end
data/lib/gliffy/url.rb ADDED
@@ -0,0 +1,67 @@
1
+ require 'gliffy/config'
2
+
3
+ module Gliffy
4
+ # Handles signing and assembling the URL
5
+ class SignedURL
6
+
7
+ def initialize(api_key,secret_key,url_root,url)
8
+ raise ArgumentError.new("api_key is required") if !api_key
9
+ raise ArgumentError.new("secret_key is required") if !secret_key
10
+ raise ArgumentError.new("url_root is required") if !url_root
11
+ raise ArgumentError.new("url is required") if !url_root
12
+ @logger = Logger.new(Config.config.log_device)
13
+ @logger.level = Config.config.log_level
14
+ @params = Hash.new
15
+ @params['apiKey'] = api_key
16
+ @secret_key = secret_key
17
+ @url_root = url_root
18
+ @url = url
19
+ end
20
+
21
+ # Sets a request parameter
22
+ #
23
+ # [param] the name of the parameter, as a string
24
+ # [value] the value of the parameter, unencoded
25
+ #
26
+ def []=(param,value)
27
+ if (param == 'apiKey')
28
+ raise ArgumentError.new('You may not override the api_key in this way')
29
+ end
30
+ @params[param] = value
31
+ end
32
+
33
+ # Sets all request parameters to those in the hash.
34
+ def params=(params_hash)
35
+ api_key = @params['apiKey']
36
+ @params.replace(params_hash)
37
+ @params['apiKey'] = api_key
38
+ end
39
+
40
+ # Gets the full URL, signed and ready to be requested
41
+ def full_url
42
+ @logger.debug("Getting full_url of #{@url}")
43
+ to_sign = @url
44
+ url_params = Hash.new
45
+ @params.keys.sort.each do |key|
46
+ @logger.debug("Adding param #{key} (#{to_sign.class.to_s}, #{key.class.to_s}) : #{to_sign.to_s}")
47
+ to_sign += key
48
+ to_sign += @params[key].to_s
49
+ url_params[key.to_s] = @params[key].to_s
50
+ end
51
+ to_sign += @secret_key
52
+ @logger.debug("Signing '#{to_sign}'")
53
+ signature = Digest::MD5.hexdigest(to_sign)
54
+ signature.gsub!(/^0/,'') while (signature =~ /^0/)
55
+ @logger.debug("signature == '#{signature}'")
56
+ url_params['signature'] = signature
57
+
58
+ url = @url_root + @url + '?'
59
+ url_params.keys.sort.each do |key|
60
+ val = CGI::escape(url_params[key])
61
+ url += "#{key}=#{val}&"
62
+ end
63
+ url.gsub!(/\&$/,'')
64
+ return url
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,72 @@
1
+ require 'rexml/document'
2
+ require 'array_has_response'
3
+ require 'gliffy/rest'
4
+
5
+ include REXML
6
+
7
+ module Gliffy
8
+
9
+ # A user token
10
+ class UserToken < Response
11
+ attr_reader :expiration
12
+ attr_reader :token
13
+ def self.from_xml(element)
14
+ expiration = Time.at(element.attributes['expiration'].to_i / 1000)
15
+ token = element.text
16
+ UserToken.new(expiration,token)
17
+ end
18
+
19
+ def expired?
20
+ Time.now > expiration
21
+ end
22
+
23
+ def initialize(expiration,token)
24
+ super()
25
+ @expiration = expiration
26
+ @token = token
27
+ end
28
+
29
+ end
30
+
31
+ class Users < ArrayResponseParser; end
32
+
33
+ # A user of Gliffy and the main entry point to using the API (see #initiate_session)
34
+ class User < Response
35
+
36
+ # The user's username, which is their identifier within an account
37
+ attr_reader :username
38
+ # The user's email, which is unique to them in the entire Gliffy system.
39
+ # Note that this isn't guaranteed to be a real email, nor is
40
+ # it guaranteed to be the user's actual email. This is
41
+ # assigned by the system unless overridden by the API.
42
+ attr_reader :email
43
+ attr_reader :id
44
+
45
+ def self.from_xml(element)
46
+ id = element.attributes['id'].to_i
47
+ is_admin = false
48
+ is_admin = element.attributes['is-admin'] == 'true' if element.attributes['is-admin']
49
+ username = element.elements['username'] ? element.elements['username'].text : nil
50
+ email = element.elements['email'] ? element.elements['email'].text : nil
51
+
52
+ User.new(id,is_admin,username,email)
53
+ end
54
+
55
+ # Returns true if this user is an admin of the account in which they live
56
+ def is_admin?
57
+ @is_admin
58
+ end
59
+
60
+ protected
61
+
62
+ def initialize(id,is_admin,username,email)
63
+ super()
64
+ @id = id
65
+ @is_admin = is_admin
66
+ @username = username
67
+ @email = email
68
+ end
69
+
70
+ end
71
+
72
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: davetron5000-gliffy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - David Copeland
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-12-22 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: technoweenie-rest-client
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.5.1
23
+ version:
24
+ description:
25
+ email: davidcopeland@naildrivin5.com
26
+ executables:
27
+ - gliffy
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - README.rdoc
32
+ files:
33
+ - ext/array_has_response.rb
34
+ - lib/gliffy/account.rb
35
+ - lib/gliffy/cli.rb
36
+ - lib/gliffy/commands/commands.rb
37
+ - lib/gliffy/config.rb
38
+ - lib/gliffy/diagram.rb
39
+ - lib/gliffy/folder.rb
40
+ - lib/gliffy/gliffy.rb
41
+ - lib/gliffy/response.rb
42
+ - lib/gliffy/rest.rb
43
+ - lib/gliffy/url.rb
44
+ - lib/gliffy/user.rb
45
+ - lib/gliffy.rb
46
+ - bin/gliffy
47
+ - README.rdoc
48
+ has_rdoc: true
49
+ homepage: http://davetron5000.github.com/gliffy
50
+ post_install_message:
51
+ rdoc_options:
52
+ - --title
53
+ - Gliffy Ruby Client
54
+ - --main
55
+ - README.rdoc
56
+ - -ri
57
+ require_paths:
58
+ - lib
59
+ - ext
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ requirements: []
74
+
75
+ rubyforge_project:
76
+ rubygems_version: 1.2.0
77
+ signing_key:
78
+ specification_version: 2
79
+ summary: client to access the Gliffy API
80
+ test_files: []
81
+