davetron5000-gliffy 0.1.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.
@@ -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
+