davetron5000-gliffy 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,70 +1,197 @@
1
- <em>The Gliffy API is currently in private beta. This will be a Ruby implementation to access your Gliffy account.</em>
1
+ This is the Ruby client library for interacting with Gliffy[http://www.gliffy.com]. It's main function is for you to integrate Gliffy documents into the workflow of another application.
2
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.
3
+ = Getting Started
4
4
 
5
- == Client Library
5
+ sudo gem install gliffy
6
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
7
+ = Overview
8
8
 
9
- require 'gliffy'
9
+ The main entry point to Gliffy is Gliffy::Handle, which provides high-level access to most features available from the API. You should instantiate one of these objects per <i>user session</i>. To create it, you will need to create and populate an instance of the Credentials class. This class is constructed almost entirely from static data about your Gliffy account, so you will probably configure an instance of this globally.
10
+
11
+ This is then used (along with the API root to Gliffy) to create an instance of Gliffy::Handle. Objects of this class provide access to the features you will need to integrate Gliffy into your app's workflow.
12
+
13
+ == Example
10
14
 
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'
15
+ Suppose you have created a group blog application using Rails and wish to give Blog authors the ability to use Gliffy diagrams. In <tt>config/initializers/gliffy.rb</tt> you might configure values for the Credential object
14
16
 
15
- handle = Gliffy::Handle.new('lumberg@initech.com')
17
+ $gliffy_api_key = 'your-consumer-key-here'
18
+ $gliffy_secret = 'your-secret-here'
19
+ $gliffy_app_description = 'My Awesome Group Blog',
20
+ $gliffy_account_id = 655321
21
+ $gliffy_root = 'www.gliffy.com/api/v1'
22
+ $gliffy_edit_root = 'www.gliffy.com/gliffy'
16
23
 
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")
24
+ Then, in your <tt>sessions_controller.rb</tt>:
25
+
26
+ require 'gliffy'
27
+
28
+ def create
29
+ self.current_user = User.authenticate(params[:email],params[:password])
30
+ if logged_in?
31
+ # Whatever you do when they log in successfully
32
+ # Then create the credentials object
33
+ cred = Credentials.new(\
34
+ $gliffy_api_key,
35
+ $gliffy_secret,
36
+ $gliffy_app_description,
37
+ $gliffy_account_id,
38
+ self.current_user.username)
39
+ session[:gliffy] = Gliffy::Handle.new($gliffy_root,$gliffy_edit_root,cred)
40
+ end
20
41
 
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.
42
+ Now you can use the gliffy handle in a controller or a view. Perhaps you'd make an action to create a new document and send the user to edit it:
22
43
 
23
- * RDoc is available a http://davetron5000.github.com/gliffy
24
- * Source is available at http://github.com/davetron5000/gliffy/tree/master
44
+ def create
45
+ new_doc = session[:gliffy].document_create(params[:name])
46
+ redirect_to(session[:gliffy].document_edit_link(new_doc.document_id,
47
+ {:returnURL => url_for(:controller => 'return_from_gliffy'),
48
+ :returnButtonText => 'Back to My Awesome Blog'}))
49
+ end
25
50
 
26
- == Command Line Client
51
+ == Digging Deeper
27
52
 
28
- +gliffy+ +help+ shows a list of commands. Currently, there are:
53
+ If you wish to bypass the high-level API, you can interact with Gliffy directly via the Gliffy::Request class, which allows you to make arbitrary requests against the Gliffy API, but takes care of signing your URLs and all OAuth things that need to be done:
29
54
 
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
55
+ # Create a Credentials object as normal
56
+ request = Gliffy::Request.new('www.gliffy.com/api/v1',credentials)
57
+ # The method name maps directly to Gliffy's "action" parameters
58
+ response = request.delete('accounts/$account_id/documents/12345')
37
59
 
38
- === Configuration
60
+ You can manipulate the response directly, or attempt to parse it using the Gliffy::Response object:
39
61
 
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:
62
+ model = Response.from_http_response(response)
41
63
 
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
64
+ = Command Line Client
46
65
 
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:
66
+ This also comes with a command line client that can serve as an example of using the API. The command-line client is quite
67
+ usable in its own right:
48
68
 
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.
69
+ gliffy help
51
70
 
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.
71
+ This will list all the commands you can give to the +gliffy+ command. You can't do *everything* with the command line that you can with the full API, but you can do quite a bit
53
72
 
54
- === Example
73
+ # set up your account
74
+ > gliffy config
55
75
 
76
+ # List all documents in your account
56
77
  > gliffy ls
57
- 1573119 Deployment Artifacts
58
- 1569470 Monthly_Eligible
59
- 1569477 Monthly_Ineligibile
60
- 1569478 Quarterly_Eligible
61
- 1569479 Quarterly_Ineligibile
62
- > gliffy get 1569479
63
- Quarterly_Ineligibile.jpg
64
- > gliffy get 1569479 -d ~/Downloads -t png
65
- /Users/davec/Downloads/Quarterly_Ineligibile.png
66
- > gliffy edit 1569470
67
- # You are sent to gliffy.com in your browser to edit that diagram
68
- > gliffy new -e "Class Diagram"
69
- # You are sent to gliffy.com to edit the new diagram
70
78
 
79
+ # Create a new document
80
+ > gliffy new "My New Document"
81
+ Created document 123456 - My New Document
82
+
83
+ # Edit it
84
+ > gliffy edit 123456
85
+
86
+ # Make a new folder
87
+ > gliffy mkdir awesome
88
+
89
+ # Move our new document there
90
+ > gliffy mv 123456 awesome
91
+
92
+ # Get it as a PNG
93
+ > gliffy get -t png 123456
94
+ Wrote 123456_L.png
95
+
96
+ # Get help on a command
97
+ > bin/gliffy help get
98
+ view [options]
99
+ View a diagram as an image, or download it
100
+
101
+ Options:
102
+ -p, --publicurl - Get the Public URL only (if
103
+ possibe)
104
+ -s, --size=L, M, S, T - Size (default: L)
105
+ -t, --type=jpeg, png, svg, xml - File Type (default: jpeg)
106
+ -u, --url - Get the URL only
107
+ -v, --version=version number (omit for latest) - Version
108
+
109
+ = Design
110
+
111
+ == Domain Objects
112
+
113
+ Instead of creating explicit objects for each domain object in Gliffy, we always return a Response object, that uses method_missing to implement accessors for data returned from Gliffy. These implicit accessors should return typed values and are named accordingly:
114
+ * If the name in the XSD[http://www.gliffy.com/developer/apidocs/xsddoc/] has dashes, underscores are used here
115
+ * If the item is a boolean, its boolean value is available with a "?" at the end
116
+ * The id field is available as type_id, e.g. document_id
117
+ * Date fields are converted to Time objects
118
+ * Any field in the response that was not known about in this code will be available as a String, based on the above rules
119
+
120
+ So, if you requested document meta data, you would have the following accessors available:
121
+
122
+ * document.document_id
123
+ * document.is_private?
124
+ * document.is_public?
125
+ * document.num_versions
126
+ * document.mod_date # returns a Time
127
+ * document.create_date # returns a Time
128
+ * document.published_date # returns a Time
129
+ * document.owner # Returns a Response that responds to user accessors
130
+ * document.versions # Returns an array of Response objects that act like versions
131
+
132
+ == HTTP Layer
133
+
134
+ Request implements the HTTP layer, and is based on HTTParty. Since all Gliffy URLs have an "action" HTTP param in them, this action is the method name, followed by the URL on which to perform that action (this is not a REST action, but specific to Gliffy). You can optionally include other HTTP params, however those needed for authentication and signing are taken care of. Request will examine the Credential object used to create the Request object, sign the request, make the request and return the result. It will look at the result only enough to determine if it's an error, or a failure. See the RubyDoc for more on how this works.
135
+
136
+ = Development
137
+
138
+ == Gems
139
+
140
+ You will need:
141
+
142
+ * hanna 0.1.7, available via `gem install mislav-hanna`
143
+ * httparty 0.4.2 or better
144
+ * ruby-hmac 0.3.2 or better
145
+ * gli 0.1.6 or better
146
+
147
+ All of these save for hanna are installed if you installed the gem.
148
+
149
+ == Unit Tests
150
+
151
+ Make sure you get at least 100% statement coverage of the code you write via Unit Tests.
152
+
153
+ Sometimes the test that two nonces shouldn't be the same fails. This occurs, because they are generated in pretty much the same instant AND when the random number generator generates the same number twice in a row. Usually if you run tests again, things pass.
154
+
155
+ == Integration Tests
156
+
157
+ This code is capable of running integration tests against Gliffy's integration test servers.
158
+ If you would like to run these tests, you must contact Gliffy for the information needed.
159
+ You could technically run integration tests against your own Gliffy account on their production
160
+ server, but this may delete or change your account's data and is not recommended. Once you
161
+ have the information from Gliffy, create the file `test/it_cred.rb` as follows:
162
+
163
+ $account_id = # integration tests account id
164
+ $username = # integration tests admin user name
165
+ $oauth_consumer_key = # integration test account consumer key
166
+ $oauth_consumer_secret = # integration test account consumer secret
167
+ $api_root = # integration test server API endpoint
168
+ $http_auth_username = # integration test server HTTP Auth username
169
+ $http_auth_password = # integration test server HTTP Auth password
170
+
171
+ == Functional Tests
172
+
173
+ The functional tests perform actual workflows against a Gliffy server and, as such, are more fragile. If something is wrong in your environment (or with Gliffy), you could leave the test account in a weird state. As such, you should create a new account using a test-only API call. This can be done via
174
+
175
+ rake setup_account
176
+
177
+ This requires that it_cred.rb is set up and runs test/setup_account.rb. This will create the file functest_cred.rb with the necessary information to access the newly created account. The accounts seem to get reset every day, so you will not be able to reliably automate this. That being said, the only way to get 100% coverage is to run these tests.
178
+
179
+ Each functional test assumes the following:
180
+
181
+ * The account name is 'Ruby Client Test Account'
182
+ * The account id is 1000001
183
+ * The only user is testuser@gliffy.com
184
+ * There are no documents/diagrams
185
+ * The only folder is ROOT
186
+
187
+ Each test will put data into Gliffy, query it, and remove it, thus leaving the account in the same state.
188
+
189
+ To fully test the edit launch link, run
190
+
191
+ rake TEST_LINK=true functest
192
+
193
+ This will print out the launch link and pause the testing. Copy/Paste this into your browser to make sure it works and then come back to the console and hit return. Do not do this for automated builds.
194
+
195
+ == JUnit output
196
+
197
+ I monkeypatched the Ruby unit test classes to output JUnit-style XML when the tests are run. I believe this file gets overridden with each type of test, but you only really should care about it for the `test` target. The file is called `junit_output.xml`.
data/bin/gliffy CHANGED
@@ -1,36 +1,312 @@
1
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'
2
+ $: << File.expand_path(File.dirname(__FILE__) + '/../lib')
3
+ $: << File.expand_path(File.dirname(__FILE__) + '/../ext')
7
4
  require 'rubygems'
8
5
  require 'gli'
6
+ require 'etc'
7
+ require 'gliffy'
8
+
9
+ $description = 'Gliffy Command Line Client'
10
+
9
11
  include GLI
10
12
 
11
- pre do |global_options,command,options,args|
12
- if global_options[:version]
13
- puts "#{$0} v#{Gliffy::VERSION}"
14
- false
15
- elsif !Gliffy::CLIConfig.instance.load
16
- puts "Problem loading config"
13
+ desc 'Location of your gliffy configuration'
14
+ default_value Etc.getpwuid.dir + '/.gliffyrc'
15
+ arg_name 'path to gliffy config file'
16
+ flag [:config]
17
+
18
+ #desc 'Use gob-go instead of the real gliffy (devs only)'
19
+ #switch [:gobgotest]
20
+
21
+ desc 'Delete a folder'
22
+ arg_name 'path (relative to ROOT) of folders you want delete'
23
+ command [:rmdir,:rd] do |c|
24
+ c.action do |global_options,options,args|
25
+ args.each do |path|
26
+ $handle.folder_delete(path)
27
+ puts "Deleted #{path}"
28
+ end
29
+ end
30
+ end
31
+
32
+ desc 'Create a new folder'
33
+ arg_name 'folders you want created inside the ROOT folder'
34
+ command [:mkdir,:md] do |c|
35
+ c.action do |global_options,options,args|
36
+ args.each do |path|
37
+ $handle.folder_create(path)
38
+ puts "Created #{path}"
39
+ end
40
+ end
41
+ end
42
+
43
+ desc 'Move diagram to a new folder'
44
+ arg_name 'document_id full_folder_path'
45
+ command [:mv,:move] do |c|
46
+ c.action do |global_options,options,args|
47
+ if args.length == 2
48
+ $handle.document_move(args[0],args[1])
49
+ else
50
+ raise "Must specify the document id and folder path only"
51
+ end
52
+ end
53
+ end
54
+
55
+ desc 'List folders'
56
+ command [:lsf,:lsfolders] do |c|
57
+ def output_folder(f)
58
+ puts f.path
59
+ f.child_folders.each do |child|
60
+ output_folder(child)
61
+ end
62
+ end
63
+
64
+ c.action do |global_options,options,args|
65
+ folders = $handle.account_folders
66
+ folders.each do |folder|
67
+ output_folder(folder)
68
+ end
69
+ end
70
+ end
71
+
72
+ desc 'List diagram ids and names'
73
+ arg_name 'Folder to list, omit for all folders'
74
+ command [:ls,:list] do |c|
75
+
76
+ c.desc 'Show id, public?, versions, owner, update date, name'
77
+ c.switch :l
78
+
79
+ c.desc 'Sort by id'
80
+ c.switch :i
81
+
82
+ c.desc 'Sort by mod date'
83
+ c.switch :t
84
+
85
+ c.action do |global_options,options,args|
86
+ if args.size == 1
87
+ documents = $handle.folder_documents(args[0])
88
+ elsif args.size == 0
89
+ documents = $handle.user_documents
90
+ else
91
+ raise "Either zero or one folder names are supported"
92
+ end
93
+
94
+ sorted = documents.sort{|a,b| a.name <=> b.name} if !options[:i] && !options[:t]
95
+ sorted = documents.sort{|a,b| a.mod_date <=> b.mod_date} if options[:t]
96
+ sorted = documents.sort{|a,b| a.document_id <=> b.document_id} if options[:i]
97
+
98
+ sorted.each do |doc|
99
+ if options[:l]
100
+ printf "%8d %s %4d %20s %18s %s\n",doc.document_id,doc.is_public? ? "P" : "-",doc.num_versions,doc.owner.username[0..19],doc.mod_date.strftime("%Y-%m-%d %H:%M:%S"),doc.name
101
+ else
102
+ puts "#{doc.document_id} - #{doc.name}"
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ desc 'Delete a diagram'
109
+ command [:rm,:delete] do |c|
110
+ c.action do |global_options,options,args|
111
+ args.each do |document_id|
112
+ $handle.document_delete(document_id)
113
+ puts "Deleted #{document_id}"
114
+ end
115
+ end
116
+ end
117
+
118
+ desc 'Edit a diagram'
119
+ command :edit do |c|
120
+
121
+ c.desc 'URL to return to after editing is complete'
122
+ c.default_value 'http://www.gliffy.com'
123
+ c.flag [:u,:url]
124
+
125
+ c.desc 'Text on the "Return" button in Gliffy'
126
+ c.default_value 'Return'
127
+ c.flag [:t,:text]
128
+
129
+ c.desc 'Command to run to open URL in browser'
130
+ c.default_value RUBY_PLATFORM =~ /^universal-darwin/ ? 'open' : nil
131
+ c.flag [:o,:openwith]
132
+
133
+ c.action do |global_options,options,args|
134
+ if args.length == 1
135
+ url = $handle.document_edit_link(args[0],options[:u],options[:t])
136
+ opened = false
137
+ if options[:o]
138
+ opened = system "#{options[:o]} \"#{url}\""
139
+ end
140
+ if !opened
141
+ puts "Problem running #{options[:o]}" if options[:o]
142
+ puts "Go here in your browser"
143
+ puts url
144
+ end
145
+ else
146
+ $stderr.puts "Provide exactly one document id"
147
+ end
148
+ end
149
+ end
150
+
151
+ desc 'View a diagram as an image, or download it'
152
+ command [:view,:get] do |c|
153
+
154
+ c.desc 'File Type'
155
+ c.default_value 'jpeg'
156
+ c.arg_name 'jpeg, png, svg, xml'
157
+ c.flag [:t,:type]
158
+
159
+ c.desc 'Size'
160
+ c.default_value 'L'
161
+ c.arg_name 'L, M, S, T'
162
+ c.flag [:s,:size]
163
+
164
+ c.desc 'Version'
165
+ c.arg_name 'version number (omit for latest)'
166
+ c.flag [:v,:version]
167
+
168
+ c.desc 'Get the URL only'
169
+ c.switch [:u,:url]
170
+
171
+ c.desc 'Get the Public URL only (if possibe)'
172
+ c.switch [:p,:publicurl]
173
+
174
+ c.action do |global_options,options,args|
175
+ args.each do |document_id|
176
+ version = options[:v]
177
+ version_name = ''
178
+ version_name = "_V#{version}" if version
179
+ if options[:u]
180
+ puts $handle.document_get_url(document_id,options[:t].to_sym,options[:s].to_sym,version)
181
+ elsif options[:p]
182
+ document = $handle.document_get_metadata(document_id)
183
+ if document.is_public?
184
+ # This isn't formally documented in the API so we put it here
185
+ puts "http://www.gliffy.com/pubdoc/#{document.document_id}/#{options[:s]}.jpg"
186
+ else
187
+ puts "Document is not public"
188
+ puts $handle.document_get_url(document_id,options[:t].to_sym,options[:s].to_sym,version)
189
+ end
190
+ else
191
+ bytes = $handle.document_get(document_id,options[:t].to_sym,options[:s].to_sym,version)
192
+ filename = "#{document_id}_#{options[:s]}#{version_name}.#{options[:t]}"
193
+ File.open(filename,'wb') do |f|
194
+ f.write(bytes)
195
+ end
196
+ puts "Wrote #{filename}"
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ desc 'Create a new diagram'
203
+ arg_name 'Name of the diagram'
204
+ command :new do |c|
205
+
206
+ c.desc 'Full path to the folder in which this diagram should ilve'
207
+ c.flag [:f,:folder]
208
+
209
+ c.desc 'Id of a document to use as a template'
210
+ c.flag [:t,:template]
211
+
212
+ c.action do |global_options,options,args|
213
+ if args.length > 0
214
+ new_document = $handle.document_create(args.join(" "),options[:f],options[:t])
215
+ puts "Created document #{new_document.document_id} - #{new_document.name}"
216
+ else
217
+ $stderr.puts "You must supply the diagram name"
218
+ end
219
+ end
220
+ end
221
+
222
+ desc 'Modify configuration (currently only create)'
223
+ command :config do |c|
224
+
225
+ c.desc 'Force a recreation of your config file, even if it exists'
226
+ c.switch :force
227
+
228
+ c.action do |global_options,options,args|
229
+ if $config.nil? || options[:force]
230
+ puts "What is account ID?"
231
+ id = $stdin.gets.chomp
232
+ puts "What is your Consumer Key?"
233
+ key = $stdin.gets.chomp
234
+ puts "What is your Consumer Secret?"
235
+ secret = $stdin.gets.chomp
236
+ puts "What is the username or email address of an admin user?"
237
+ user = $stdin.gets.chomp
238
+ puts "About to create your configuration with the following information:"
239
+ puts "Account ID : #{id}"
240
+ puts "Consumer Key : #{key}"
241
+ puts "Consumer Secret : #{secret}"
242
+ puts "User Name : #{user}"
243
+ puts
244
+ puts "OK? (Y/N)"
245
+ response = $stdin.gets
246
+ if response =~ /^[Yy]/
247
+ cred = Gliffy::Credentials.new(key,secret,$description,id,user)
248
+ write_config(cred,global_options[:config])
249
+ puts "Wrote config to #{global_options[:config]}"
250
+ else
251
+ puts "Aborted"
252
+ end
253
+ else
254
+ $stderr.puts "You already have a config; edit it by hand or use --force to recreate"
255
+ end
256
+ end
257
+ end
258
+
259
+ pre do |global,command,options,args|
260
+ require 'yaml'
261
+ message = nil
262
+ begin
263
+ $config = File.open(global[:config]) { |f| YAML::load(f) }
264
+ rescue
265
+ message = "No config file found at #{global[:config]}\nUse #{$0} config to create one"
266
+ $config = nil
267
+ end
268
+ if $config.nil? && command.name != :config
269
+ $stderr.puts message if !message.nil?
17
270
  false
18
- elsif command && command.name != :help
19
- previous_token = Gliffy::CLIConfig.instance.config[:current_token]
20
- Gliffy::Config.config.log_level = Logger::DEBUG if global_options[:v]
21
- $gliffy = Gliffy::Handle.new(Gliffy::CLIConfig.instance.config[:username],previous_token)
22
- true
23
271
  else
272
+ if !command || command.name != :config
273
+ if global[:gobgotest]
274
+ puts "Going against gob-go -- developers only!"
275
+ class HTTPartyAuth
276
+ def post(url)
277
+ HTTParty.post(url,:basic_auth => {:username => 'gobgotest' , :password => 'gobgotest'})
278
+ end
279
+ end
280
+ $handle = Gliffy::Handle.new(
281
+ 'gob-go-stable.gliffy.com/api/1.0',
282
+ 'gob-go-stable.gliffy.com/gliffy',
283
+ $config,HTTPartyAuth.new)
284
+ else
285
+ $handle = Gliffy::Handle.new(
286
+ 'www.gliffy.com/api/1.0',
287
+ 'www.gliffy.com/gliffy',
288
+ $config)
289
+ end
290
+ token = $handle.update_token
291
+ write_config($config,global[:config])
292
+ end
24
293
  true
25
294
  end
26
295
  end
27
296
 
28
- desc 'show version'
29
- switch :version
30
-
31
- desc 'be more verbose'
32
- switch :v
297
+ post do |global,command,options,args|
298
+ # Post logic here
299
+ end
33
300
 
34
- require 'gliffy/commands'
301
+ on_error do |exception|
302
+ # Error logic here
303
+ # return false to skip default error handling
304
+ true
305
+ end
35
306
 
307
+ def write_config(cred,config)
308
+ File.open(config,'w') do |out|
309
+ YAML.dump(cred,out)
310
+ end
311
+ end
36
312
  GLI.run(ARGV)