
An Introduction to RubyCocoa, Part 2
Pages: 1, 2, 3
You'll notice that the first section of this method looks similar to the addFile
method we created earlier. That's because we're creating an instance of the NSSavePanel
, which is very similar to the NSOpenPanel
. One key difference you'll notice here is that we're calling a method called setAccessoryView
and we pass into it our custom view we created in IB. This method adds our custom view to the NSSavePanel
, which will give the user the ability to choose the type of archive file he or she wants to create when choosing a name and location for the file.
If the users chose the "OK" button from the NSSavePanel
, we create the archive for them. We start this process by first gathering all of the information from the NSSavePanel
— such as the file type, file name, and directory. Next, we use this information to construct the tar
command that will create an archive file and compress it according to the chosen file type.
After that, we create an instance of the NSAlert
class and set it to a successful message to be displayed to the user if all goes well. Now we truly begin the process of creating the archive. We use the system
method found in the Kernel
module to execute the shell commands that will create our temp directory, copy the files into it, tar
and compress the temp directory, copy the tar
red file to the chosen directory, and finally, remove the temporary directory and its contents from the system. If everything executed properly, the NSAlert
we created earlier will be displayed; otherwise, we will manipulate the NSAlert
to display an error message to the user.
If everything got copied into your project properly, and you have the correct permissions to do so, you should be able to run the application and create a new archive file. Assuming that works properly, we have half of our application's functionality working. So let's press on and get the other half working. The next portion of this section will add the ability to extract files from already existing archives.
The extractArchive
method is very similar to our createArchive
method. First, we must create an instance of the NSOpenPanel
class that will allow our users to choose the directory in which the archive file will be located. Then, it will create a tar
command to decompress and untar
the chosen file. Finally, if all goes well, it will display an alert that notifies the users of the success of the extraction, otherwise an error alert will be displayed. The following code should look somewhat familiar and should be copied into our extractArchive
method skeleton:
###
# extractArchive
# Displays an instance of the NSOpenPanel and
# gets the directory in which the extracted
# files will reside. Then, it extracts the
# archived file to that directory.
###
def extractArchive(sender)
oPanel = NSOpenPanel.openPanel
oPanel.setCanChooseFiles(false)
oPanel.setCanChooseDirectories(true)
buttonClicked = oPanel.runModal
if buttonClicked == NSOKButton
filename =
@archiveFile.stringValue.to_s
filetype = filename.split('.')[1]
directory =
oPanel.filenames.objectAtIndex(0)
# Create the tar extraction command
case filetype
when "tgz"
tarCommand = "tar -xvzf " +
"#{filename} -C #{directory}"
when "bz2"
tarCommand = "tar -xvjf " +
"#{filename} -C #{directory}"
when "Z"
tarCommand = "tar -xvZf " +
"#{filename} -C #{directory}"
when "tar"
tarCommand = "tar -xvf " +
"#{filename} -C #{directory}"
end
# Create an alert dialog to display
# the outcome of the tar command
alert = NSAlert.alloc.init
alert.setMessageText(
"Extraction Successful")
alert.setInformativeText(
"The tar file was successfully " +
"extracted")
alert.setAlertStyle(
NSInformationalAlertStyle)
alert.addButtonWithTitle("Ok")
# Extract the files from the archive
begin
system(tarCommand)
rescue
alert.setMessageText(
"Extraction Unsuccessful")
alert.setInformativeText(
"An error occurred while " +
"extracting the archived " +
"file.\nMake sure you have " +
"the correct permissions " +
"and the chosen file exists.")
alert.setAlertStyle(
NSCriticalAlertStyle)
end
alert.beginSheetModalForWindow(
@mainWindow,
:modalDelegate, self,
:didEndSelector, nil,
:contextInfo, nil)
end
end
In the extractArchive
method, the first thing you'll notice is that we create an instance of the NSOpenPanel
class; However, this instance is implemented slightly different than the one we created for the addFile
method. We set up this panel so that only directories can be chosen — not files — and we went with the default of allowing only a single selection.
After this we see something that looks very much like the createArchive
method. We create a tar
command string to extract the files from the chosen archive into the directory that was selected in the NSOpenPanel
. Next, we create an instance of the NSAlert
class and call the system
command to execute the tar
command string we created in the last step. Finally, we display an alert message to notify the user of the success of the operation. If the system
command ran into problems we catch it using the rescue
clause and display an error message instead.
There's only one thing still missing from our application, and that is one final piece of convenience. Rather than having the users type in the long and tedious names of the files they wish to extract, we need to implement a method that allows the users to select the file using an NSOpenPanel
instead. Our browseForArchive
method does just this, and its implementation can be found below.
###
# browseForArchive
# Pops up an instance of the NSOpenPanel and
# allows the user to select the archive they
# wish to open.
###
def browseForArchive(sender)
# Create an array of the file types
# allowed in the NSOpenPanel
filetypes = ["tgz", "bz2", "Z", "tar"]
# Create the NSOpenPanel and get the
# archive file to extract
oPanel = NSOpenPanel.openPanel
oPanel.setAllowsMultipleSelection(false)
buttonClicked =
oPanel.runModalForDirectory(nil,
:file, nil,
:types, filetypes)
if buttonClicked == NSOKButton
file =
oPanel.filenames.objectAtIndex(0)
@archiveFile.setStringValue(file)
end
end
Again, we find ourselves in familiar territory with just a few differences from what we saw earlier. The first thing you'll notice is that once again we are creating a new NSOpenPanel
object. However, this time around we are only letting the user select specific file types. These file types are the four that we have chosen to deal with in our application and can be found in the filetypes
array we created just before creating our NSOpenPanel
instance. Once, we have displayed the open panel we make sure the user pressed the "OK" button and then we set the archiveFile
NSTextField
to display the name of the file the user has just chosen. This method allows our application to be a bit speedier and less error-prone than it would be if it counted on the users typing in the full name of the file they wish to decompress and extract.
Final Thoughts
Well, that's it. You should now have a fully functioning RubyCocoa application. Hopefully, the trip was fun and entertaining, and if you're lucky you even got an application that you may put to use in the end. Just in case you had any trouble along the way — or if you just followed along and didn't participate in the tutorial — I have placed a copy of the Xcode project for this article online here. Do with it what you will, and maybe even try adding in some of the suggestions I've listed below.
Obviously, there are still several areas in which this application could be improved. One area this application could definitely be enhanced is in the number of supported file extensions. Right now the application only supports four different file extensions, but there are many more, as well as compression techniques that could be added to this application to make it even more robust. You could also look into changing all of the open and save panels into sheets rather than modal dialogues. Another great feature would be the ability to open an already existing archive and then add and remove files from it.
All of these are great ways to extend this application and make it something that you use on a daily basis. So those of you out there who enjoyed this article, I believe you have some homework to keep you busy for quite awhile. If you make some good changes send them to me and I'll see if I can't find somewhere to post them for others to get them; just remember to send me the full code.
One last note: I just wanted to share with those of you who have followed my articles up till now. I have really enjoyed writing these tutorials, and I am already formulating some ideas for other Ruby articles in the near future. So if you've liked this series on Ruby programming so far, keep on the lookout for a new batch of Ruby articles from me very soon.
Christopher Roach recently graduated with a master's in computer science and currently works in Florida as a software engineer at a government communications corporation.
Return to MacDevCenter.com.

-
Runtime Errors
2007-12-29 23:01:23 Altrius [View]
-
Ruby-esque
2005-03-08 17:17:43 n9yty [View]
-
Code is hard to read
2005-03-05 06:06:11 MrN [View]
-
Class Controller not found
2004-12-08 14:37:48 chmeee [View]
-
RubyCocoa Binary for Panther (OS X v10.3)
2004-11-16 06:44:25 Christopher Roach |[View]
-
Installer grief
2004-10-26 04:51:21 Snarke [View]
-
Installer grief
2004-11-07 18:22:59 Christopher Roach |[View]
-
Having install troubles
2004-10-16 10:18:31 allClass [View]
-
Having install troubles
2004-10-16 17:26:44 Christopher Roach |[View]
-
Having install troubles
2004-11-07 12:50:28 leeg [View]
-
Having install troubles
2004-11-07 18:25:12 Christopher Roach |[View]
