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.
data/README.rdoc ADDED
@@ -0,0 +1,52 @@
1
+ <em>The Gliffy API is currently in private beta. This will be a Ruby implementation to access your Gliffy account.</em>
2
+
3
+ This consists of a Ruby client for Gliffy as well as a simple command line tool to access your Gliffy account using that client.
4
+
5
+ == Client Library
6
+
7
+ Main entry point is Gliffy::Handle, though you should look at Gliffy::Config for configuration options. Here's an example of getting the list of diagrams and then downloading the first one as a JPEG
8
+
9
+ require 'gliffy'
10
+
11
+ Gliffy::Config.config.api_key='aa9d0e8d-449b-44ad-904a-bf87deb7c403'
12
+ Gliffy::Config.config.secret_key='a52585f7-5952-4229-8bbe-b5787521b571'
13
+ Gliffy::Config.config.account_name='Initech'
14
+
15
+ handle = Gliffy::Handle.new('lumberg@initech.com')
16
+
17
+ diagrams = handle.get_diagrams
18
+ diagram_name_safe = diagrams[0].name.gsub(/ /,'_')
19
+ handle.get_diagram_as_image(diagrams[0].id,:mime_type => :jpeg,:file=>"#{diagram_name_safe}.jpg")
20
+
21
+ The Gliffy::Handle is a <b>user-session based connection</b> to Gliffy. You shoudl therefore engineer your application to keep one of these per user who will access Gliffy and *not* make a global instance.
22
+
23
+ * RDoc is available a http://davetron5000.github.com/gliffy
24
+ * Source is available at http://github.com/davetron5000/gliffy/tree/master
25
+
26
+ == Command Line Client
27
+
28
+ +gliffy+ +help+ shows a list of commands. Currently, there are:
29
+
30
+ [+delete+] Delete a diagram (also: del,rm)
31
+ [+edit+] Edit a diagram
32
+ [+get+] Download a diagram as an image to a file
33
+ [+help+] Show commands
34
+ [+list+] List all diagrams in the account (also: ls)
35
+ [+new+] Create a new diagram
36
+ [+url+] Get the URL for an image
37
+
38
+ === Configuration
39
+
40
+ The first time you run the client, it will create a base configuration in your home directory called <tt>.gliffyrc</tt>, and will ask you to provide it with four pieces of information:
41
+
42
+ [API Key] This is the API Key given to you by Gliffy
43
+ [Secret Key] This is the Secret Key given to you by Gliffy. <b>Do not check this value into source control</b>
44
+ [Account Name] Your account's name. This should've been provided with your API Key
45
+ [Username] The username to work under. The command line client only allows single-user access to your Gliffy account. If you just signed up for Gliffy, this is probably the email address you used to sign up
46
+
47
+ If you are not on OS X, you will want to configure two other options, and you can do this by editing your <tt>.gliffyrc</tt> directly:
48
+
49
+ [<tt>open_image</tt>] Configures the command for opening an image from the command line. This should be a string of the form <tt>command %s</tt> where <tt>%s</tt> will be replaced with the name of the image file to open.
50
+ [<tt>open_url</tt>] Configures the command for opening an url from the command line. This should be a string of the form <tt>command %s</tt> where <tt>%s</tt> will be replaced with the name of the url to open.
51
+
52
+ The other options are all documented in Gliffy::Config. Note that your most previously received user token is stored here as well, to keep from getting it every time the client is run.
data/bin/gliffy ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ $: << File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $: << File.expand_path(File.dirname(__FILE__) + '/../ext')
5
+
6
+ require 'gliffy/cli'
7
+
8
+ Gliffy::Command.execute(ARGV)
@@ -0,0 +1,10 @@
1
+
2
+ class Array
3
+
4
+ def success?; @success; end
5
+ def success=(success); @success = success; end
6
+
7
+ def not_modified?; @not_modified; end
8
+ def not_modified=(not_modified); @not_modified = not_modified; end
9
+
10
+ end
data/lib/gliffy.rb ADDED
@@ -0,0 +1 @@
1
+ require 'gliffy/gliffy'
@@ -0,0 +1,55 @@
1
+ require 'rexml/document'
2
+ require 'array_has_response'
3
+ require 'gliffy/rest'
4
+
5
+ include REXML
6
+
7
+ module Gliffy
8
+
9
+ # Represents on account
10
+ class Account < Response
11
+
12
+ attr_reader :name
13
+ attr_reader :id
14
+ # Either :basic or :premium
15
+ attr_reader :type
16
+ attr_reader :max_users
17
+ # A Time representing the date on which this account expires
18
+ attr_reader :expiration_date
19
+
20
+ attr_reader :users
21
+
22
+ def self.from_xml(element)
23
+ id = element.attributes['id'].to_i
24
+ type = element.attributes['account-type']
25
+ if type == 'Basic'
26
+ type = :basic
27
+ elsif type == 'Premium'
28
+ type = :premium
29
+ else
30
+ raise "Unknown type #{type}"
31
+ end
32
+ max_users = element.attributes['max-users'].to_i
33
+ expiration_date = Time.at(element.elements['expiration-date'].text.to_i / 1000)
34
+ name = element.elements['name'].text
35
+ users = Users.from_xml(element.elements['users'])
36
+
37
+ Account.new(id,type,name,max_users,expiration_date,users)
38
+ end
39
+
40
+ protected
41
+
42
+ def initialize(id,type,name,max_users,expiration_date,users=nil)
43
+ super()
44
+ @id = id
45
+ @type = type
46
+ @name = name
47
+ @max_users = max_users
48
+ @expiration_date = expiration_date
49
+ @users = users
50
+ end
51
+
52
+ end
53
+
54
+ class Accounts < ArrayResponseParser; end
55
+ end
data/lib/gliffy/cli.rb ADDED
@@ -0,0 +1,260 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require 'fileutils'
3
+ require 'yaml'
4
+ require 'gliffy'
5
+ require 'logger'
6
+
7
+ module Gliffy
8
+ extend self
9
+
10
+ # A command line option to the gliffy command line client
11
+ class Command
12
+
13
+ # Global flags
14
+ GLOBAL_FLAGS = {
15
+ '-v' => 'be more verbose (overrides config)',
16
+ }
17
+
18
+ # Global access to all configured commands
19
+ def self.commands
20
+ @@commands ||= {}
21
+ end
22
+
23
+ def self.aliases
24
+ @@aliases ||= {}
25
+ end
26
+
27
+ # The name of the command
28
+ attr_reader :name
29
+ # a short description
30
+ attr_reader :description
31
+ # a usage statement
32
+ attr_reader :usage
33
+
34
+ # Create a new command
35
+ #
36
+ # [+name+] the name of the command (should be short, no spaces)
37
+ # [+description+] short description of the command
38
+ # [+offline+] true if this command doesn't require a connection to Gliffy
39
+ # [+usage+] usage statement
40
+ # [+block+] A block that represents the command itself. This block will take the gliffy handle and the args array as arguments *or* just the arguments if it is an "offline"
41
+ # command
42
+ def initialize(name,description,offline,usage,block)
43
+ @name = name
44
+ @description = description
45
+ @block = block
46
+ @offline = offline
47
+ @usage = usage ? usage : ""
48
+ end
49
+
50
+ # Runs the command with the given arguments
51
+ def run(args)
52
+ if (@offline)
53
+ @block.call(args)
54
+ else
55
+ previous_token = CLIConfig.instance.config[:current_token]
56
+ handle = Gliffy::Handle.new(CLIConfig.instance.config[:username],previous_token)
57
+ @block.call(handle,args)
58
+ CLIConfig.instance.config[:current_token] = handle.current_token
59
+ CLIConfig.instance.save
60
+ end
61
+ end
62
+
63
+ # Executes the command line that was given
64
+ def self.execute(argv)
65
+ globals = Hash.new
66
+ command = argv.shift
67
+ while !command.nil? && (command =~ /^-/) && !argv.empty?
68
+ globals[command] = true
69
+ command = argv.shift
70
+ end
71
+ Gliffy::Config.config.log_level = Logger::DEBUG if globals['-v']
72
+ cmd = Gliffy::Command.commands[command.to_sym]
73
+ if cmd
74
+ cmd.run argv
75
+ else
76
+ puts "Unknown command #{command}"
77
+ Gliffy::Command.commands[:help].run []
78
+ end
79
+ end
80
+ end
81
+
82
+ # Represents the configuration for the command line client.
83
+ # This is a singleton
84
+ class CLIConfig
85
+
86
+ @@instance = nil
87
+
88
+ # Access to the singleton
89
+ def self.instance
90
+ @@instance = CLIConfig.new if !@@instance
91
+ @@instance
92
+ end
93
+
94
+ # Returns the config hash
95
+ attr_reader :config
96
+
97
+ # Loads the user's rc file if it exists, creating it if not
98
+ def load
99
+ if !File.exist?(@config_file_name)
100
+ puts "#{@config_file_name} not found. Create? [y/n]"
101
+ answer = STDIN.gets
102
+ if answer =~ /^[Yy]/
103
+ save
104
+ else
105
+ puts "Aborting..."
106
+ return false
107
+ end
108
+ end
109
+ yaml_config = File.open(@config_file_name) { |file| YAML::load(file) }
110
+ if (yaml_config)
111
+ @config = yaml_config
112
+ end
113
+ @config[:open_url] = default_open_url if !@config[:open_url]
114
+ @config[:open_image] = default_open_image if !@config[:open_image]
115
+ read_config_from_user('API Key',:api_key)
116
+ read_config_from_user('Secret Key',:secret_key)
117
+ read_config_from_user('Account Name',:account_name)
118
+ read_config_from_user('Username',:username)
119
+ save
120
+ config = Gliffy::Config.config
121
+ @config.each() do |key,value|
122
+ method = key.to_s + "="
123
+ if config.respond_to? method.to_sym
124
+ if (method == 'log_device=')
125
+ if (value == 'STDERR')
126
+ config.log_device = STDERR
127
+ elsif (value == 'STDOUT')
128
+ config.log_device = STDOUT
129
+ else
130
+ config.log_device = value
131
+ end
132
+ else
133
+ config.send(method.to_sym,value)
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ # Saves the configration to the user's config file name as YAML
140
+ def save
141
+ fp = File.open(@config_file_name,'w') { |out| YAML::dump(@config,out) }
142
+ end
143
+
144
+ private
145
+ def read_config_from_user(name,symbol)
146
+ if (!@config[symbol])
147
+ puts "No #{name} configured. Enter #{name}"
148
+ @config[symbol] = STDIN.gets.chomp!
149
+ end
150
+ end
151
+
152
+ def initialize
153
+ @config_file_name = File.expand_path("~/.gliffyrc")
154
+ @config = {
155
+ :log_level => Gliffy::Config.config.log_level,
156
+ :log_device => Gliffy::Config.config.log_device.to_s,
157
+ :gliffy_app_root => Gliffy::Config.config.gliffy_app_root,
158
+ :gliffy_rest_context => Gliffy::Config.config.gliffy_rest_context,
159
+ :protocol => Gliffy::Config.config.protocol,
160
+ }
161
+ end
162
+
163
+ def default_open_url
164
+ # Cheesy defaults
165
+ if RUBY_PLATFORM =~ /win32/
166
+ # not sure, acutally
167
+ nil
168
+ elsif RUBY_PLATFORM =~ /linux/
169
+ 'firefox "%s"'
170
+ elsif RUBY_PLATFORM =~ /darwin/
171
+ 'open "%s"'
172
+ else
173
+ nil
174
+ end
175
+ end
176
+
177
+ def default_open_image
178
+ # Cheesy defaults
179
+ if RUBY_PLATFORM =~ /win32/
180
+ # not sure, acutally
181
+ nil
182
+ elsif RUBY_PLATFORM =~ /linux/
183
+ # not sure
184
+ nil
185
+ elsif RUBY_PLATFORM =~ /darwin/
186
+ 'open "%s"'
187
+ else
188
+ nil
189
+ end
190
+ end
191
+
192
+
193
+ end
194
+
195
+ # For defining commands, this specifies the description of the next command defined
196
+ def desc(description)
197
+ @next_desc = description
198
+ end
199
+
200
+ # For defining commands, this specifies if the next defined command is "offline"
201
+ def offline(bool)
202
+ @next_offline = bool
203
+ end
204
+
205
+ # For defining commands, specifies the usage statement of the next command
206
+ def usage(usage='')
207
+ @next_usage = usage
208
+ end
209
+
210
+ # defines a command. The only options supported is ":aliases" which is an array of aliases
211
+ # for the command
212
+ def command(name,options={},&block)
213
+ Command.commands[name] = Command.new(name,@next_desc,@next_offline,@next_usage,block)
214
+ if options[:aliases]
215
+ options[:aliases].each() do |a|
216
+ Command.commands[a] = Command.commands[name]
217
+ Command.aliases[a] = true
218
+ end
219
+ end
220
+ @next_usage = nil
221
+ @next_offline = false
222
+ @next_desc = nil
223
+ end
224
+
225
+ def parse_options(args)
226
+ options = Hash.new
227
+ return options if !args
228
+ i = 0
229
+ while i < args.length
230
+ inc = 2
231
+ if args[i] =~ /^-/
232
+ arg = args[i].gsub(/^-/,'')
233
+ if !args[i+1] || (args[i+1] =~ /^-/)
234
+ inc = 1
235
+ options[arg] = true
236
+ else
237
+ options[arg] = args[i+1]
238
+ end
239
+ else
240
+ break
241
+ end
242
+ i += inc
243
+ end
244
+ i.times { args.shift }
245
+ options
246
+ end
247
+
248
+ def format_date(date)
249
+ date.strftime('%m/%d/%y %H:%M')
250
+ end
251
+
252
+ end
253
+
254
+ include Gliffy
255
+ require 'gliffy/commands/commands'
256
+ if !CLIConfig.instance.load
257
+ exit -1
258
+ end
259
+
260
+
@@ -0,0 +1,149 @@
1
+ desc 'List all diagrams in the account'
2
+ usage <<eos
3
+ [-l]
4
+
5
+ -l - show all information
6
+ eos
7
+ command :list, :aliases => [:ls] do |gliffy,args|
8
+ diagrams = gliffy.get_diagrams
9
+ options = parse_options(args)
10
+ if options['l']
11
+ max = diagrams.inject(0) { |max,diagram| diagram.name.length > max ? diagram.name.length : max }
12
+ diagrams.sort.each do |diagram|
13
+ printf "%8d %s %-#{max}s %-3d %s %s %s\n",
14
+ diagram.id,
15
+ diagram.is_public? ? "P" : "-",
16
+ diagram.name,
17
+ diagram.num_versions,
18
+ format_date(diagram.create_date),
19
+ format_date(diagram.mod_date),
20
+ diagram.owner_username
21
+ end
22
+ else
23
+ printf_string = "%d %s\n"
24
+ diagrams.sort.each { |diagram| printf printf_string,diagram.id,diagram.name }
25
+ end
26
+ end
27
+
28
+ desc 'Delete a diagram'
29
+ usage 'diagram_id'
30
+ command :delete, :aliases => [:del,:rm] do |gliffy,args|
31
+ gliffy.delete_diagram(args[0])
32
+ end
33
+
34
+ desc 'Get the URL for an image'
35
+ usage <<eos
36
+ [-o] diagram_id
37
+
38
+ -o - open diagram's URL with configured :open_url command
39
+ eos
40
+ command :url do |gliffy,args|
41
+ open = args[0] == '-o'
42
+ args.shift if open
43
+ url = gliffy.get_diagram_as_url(args[0])
44
+ if open
45
+ if CLIConfig.instance.config[:open_image]
46
+ system(sprintf(CLIConfig.instance.config[:open_image],url))
47
+ else
48
+ puts "Nothing configured for #{:open_image.to_s} to open the image"
49
+ puts url
50
+ end
51
+ else
52
+ puts url
53
+ end
54
+ end
55
+
56
+ desc 'Download a diagram as an image to a file'
57
+ usage <<eos
58
+ [-v version_num] [-f filename] [-t image_type] diagram_id
59
+
60
+ image_type can be :jpeg, :png, :svg, or :xml
61
+ eos
62
+ command :get do |gliffy,args|
63
+
64
+ options = parse_options(args)
65
+ diagram_id = args.shift
66
+
67
+ version_number = options['v'].to_i if options['v']
68
+ filename = options['f'] if options['f']
69
+ type = options['t'].to_sym if options['t']
70
+ type = :jpeg if !type
71
+ if !filename
72
+ if version_number
73
+ filename = "#{diagram_id}_v#{version_number}.#{type.to_s}"
74
+ else
75
+ filename = "#{diagram_id}.#{type.to_s}"
76
+ end
77
+ end
78
+
79
+ get_options = { :mime_type => type, :file => filename }
80
+ get_options[:version] = version_number if version_number
81
+ gliffy.get_diagram_as_image(diagram_id,get_options)
82
+ puts filename
83
+ end
84
+
85
+ desc 'Edit a diagram'
86
+ usage 'diagram_id'
87
+ command :edit do |gliffy,args|
88
+ return_link = gliffy.get_diagram_as_url(args[0])
89
+ link = gliffy.get_edit_diagram_link(args[0],return_link,"Done")
90
+ if CLIConfig.instance.config[:open_url]
91
+ system(sprintf(CLIConfig.instance.config[:open_url],link.full_url))
92
+ else
93
+ puts "Nothing configured for #{:open_url.to_s} to open the url"
94
+ puts link.full_url
95
+ end
96
+ end
97
+
98
+ desc 'Create a new diagram'
99
+ usage <<eos
100
+ [-e] diagram_name
101
+
102
+ -e edit the diagram after creating it
103
+ eos
104
+ command :new do |gliffy,args|
105
+ edit = args[0] == '-e'
106
+ args.shift if edit
107
+ diagram = gliffy.create_diagram(args[0])
108
+ if edit
109
+ Gliffy::Command.commands[:edit].run [diagram.id]
110
+ else
111
+ puts "#{diagram.name} created with id #{diagram.id}"
112
+ end
113
+ end
114
+
115
+ desc 'Show commands'
116
+ offline true
117
+ usage 'command'
118
+ command :help do |args|
119
+ if args[0]
120
+ command = Command.commands[args[0].to_sym]
121
+ if command
122
+ printf "%s - %s\n",args[0],command.description
123
+ printf "usage: %s %s\n",args[0],command.usage
124
+ else
125
+ puts "No such command #{args[0]}"
126
+ end
127
+ else
128
+ command_string = " %-6s %s %s\n"
129
+ puts 'usage: gliffy [global_options] command [command_options]'
130
+ puts 'global_options:'
131
+ Command::GLOBAL_FLAGS.keys.sort.each do |flag|
132
+ printf command_string,flag,Command::GLOBAL_FLAGS[flag],''
133
+ end
134
+ puts
135
+ puts 'command:'
136
+ command_names = Command.commands.keys.sort { |a,b| a.to_s <=> b.to_s }
137
+ command_names.each() do |name|
138
+ command = Command.commands[name]
139
+ if !Command.aliases[name]
140
+ aliases = Array.new
141
+ Command.aliases.keys.each() do |a|
142
+ aliases << a if Command.commands[a] == command
143
+ end
144
+ alias_string = '(also: ' + aliases.join(',') + ')' if aliases.length > 0
145
+ printf command_string,name.to_s, command.description,alias_string
146
+ end
147
+ end
148
+ end
149
+ end