Created
May 27, 2011 19:36
-
-
Save cpowell/995979 to your computer and use it in GitHub Desktop.
A singleton class to manage a MacRuby application's data storage requirements.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# Datastore.rb | |
# A singleton class to manage a MacRuby application's data storage requirements. | |
# | |
# Chris Powell, [email protected], http://cbpowell.wordpress.com | |
# | |
# This work is licensed under a Creative Commons Attribution 3.0 Unported License. | |
# http://creativecommons.org/licenses/by/3.0/ | |
# | |
# For usage and discussion, see http://cbpowell.wordpress.com/category/macruby/ | |
# | |
class Datastore | |
# Required initialization of class variables | |
@@managedObjectModel = nil | |
@@managedObjectContext = nil | |
@@persistentStoreCoordinator = nil | |
# Just to make sure no one instantiates me :) | |
private_class_method :new | |
# Returns the support folder for the application, used to store the Core Data | |
# store file. This code uses a folder named "YOUR_APP_NAME" for | |
# the content, either in the NSApplicationSupportDirectory location or (if the | |
# former cannot be found), the system's temporary directory. | |
# | |
def self.applicationSupportFolder | |
paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, true) | |
basePath = (paths.count > 0) ? paths[0] : NSTemporaryDirectory() | |
return basePath.stringByAppendingPathComponent("YOUR_APP_NAME") | |
end | |
# The Managed Object Model (or MOM) keeps track of objects and their relationships. | |
# It doesn't care about actual persistency which is the MOC's job. | |
# | |
# We designed our model by editing a xcdatamodeld file. When we compile our app, this is | |
# compiled into a mom file and stored into a folder with the momd extension | |
# (as in mom deployment directory). This is how the application knows about the data | |
# structures and relationships to use. | |
# | |
# Returns the managed object model for the application, creating if necessary. | |
def self.mom | |
unless @@managedObjectModel | |
model_url = NSBundle.mainBundle.URLForResource("YOUR_APP_NAME", withExtension:"momd") | |
@@managedObjectModel = NSManagedObjectModel.alloc.initWithContentsOfURL(model_url) | |
end | |
@@managedObjectModel | |
end | |
# The managed object context acts as a bridge between the MOM and the actual persistence mechanism. | |
# | |
# You can think of a managed object context as an intelligent scratch pad. | |
# When you fetch objects from a persistent store, you bring temporary copies | |
# onto the scratch pad where they form an object graph (or a collection of | |
# object graphs). You can then modify those objects however you like. Unless | |
# you actually save those changes, however, the persistent store remains unaltered. | |
# | |
# Returns the managed object context (MOC) for the application (which is already | |
# bound to the persistent store coordinator for the application.) | |
# | |
def self.moc | |
unless @@managedObjectContext | |
coordinator = self.psc | |
unless coordinator | |
dict = { | |
NSLocalizedDescriptionKey => "Failed to initialize the store", | |
NSLocalizedFailureReasonErrorKey => "There was an error building up the data file." | |
} | |
error = NSError.errorWithDomain("YOUR_ERROR_DOMAIN", code:9999, userInfo:dict) | |
NSApplication.sharedApplication.presentError(error) | |
return nil | |
end | |
@@managedObjectContext = NSManagedObjectContext.alloc.init | |
@@managedObjectContext.setPersistentStoreCoordinator(coordinator) | |
end | |
@@managedObjectContext | |
end | |
# A PSC is the actual persistence mechanism, and is connected to a MOC. | |
# When you fetch objects, the MOC asks the coordinator to return those objects that match | |
# the fetch request. | |
# | |
# Returns the persistent store coordinator (PSC) for the application. This implementation | |
# creates and returns a coordinator, having added the store for the application to it. | |
# (The directory for the store is created, if necessary.) | |
# | |
def self.psc | |
unless @@persistentStoreCoordinator | |
error = Pointer.new_with_type('@') | |
fileManager = NSFileManager.defaultManager | |
applicationSupportFolder = self.applicationSupportFolder | |
unless fileManager.fileExistsAtPath(applicationSupportFolder, isDirectory:nil) | |
fileManager.createDirectoryAtPath(applicationSupportFolder, attributes:nil) | |
end | |
url = NSURL.fileURLWithPath(applicationSupportFolder.stringByAppendingPathComponent("YOUR_APP_NAME.sql")) | |
@@persistentStoreCoordinator = NSPersistentStoreCoordinator.alloc.initWithManagedObjectModel(self.mom) | |
# Could be NSBinaryStoreType, NSXMLStoreType or NSSQLiteStoreType | |
unless @@persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, | |
configuration:nil, | |
URL:url, | |
options:nil, | |
error:error) | |
NSApplication.sharedApplication.presentError(error[0]) | |
end | |
end | |
@@persistentStoreCoordinator | |
end | |
# Retrieve objects from the database. | |
# Credit to Matt Gallagher of 'Cocoa with Love' for inspiring this: http://cocoawithlove.com/2008/03/core-data-one-line-fetch.html | |
# | |
# * *Args* : | |
# - +entity_name+ -> the Core Data entity to retrieve, e.g. "Person" | |
# - +withLimit+ -> a limit on the query results, nil if no limit desired | |
# - +withOrder+ -> a string or NSSortDescriptor object to order the results, nil if none required | |
# - +withPredicate+ -> a string or NSPredicate object to constrain the results, nil if none required | |
# * *Returns* : | |
# - an array of objects | |
# * *Raises* : | |
# - +RuntimeError+ -> if there is a fetch error | |
# | |
def self.find_by_entity_name(entity_name, withLimit:limit, withOrder:string_or_sort_descriptor, withPredicate:string_or_predicate, *args) | |
request = NSFetchRequest.new | |
request.entity = self.mom.entitiesByName[entity_name.to_sym] | |
if string_or_predicate | |
if string_or_predicate.is_a?(NSString) | |
pred = NSPredicate.predicateWithFormat(string_or_predicate, argumentArray:args) | |
elsif string_or_predicate.is_a?(NSPredicate) | |
pred = string_or_predicate | |
end | |
end | |
if string_or_sort_descriptor | |
if string_or_sort_descriptor.is_a?(NSString) | |
order_by = NSSortDescriptor.alloc.initWithKey(string_or_sort_descriptor, ascending:true) | |
elsif string_or_sort_descriptor.is_a?(NSSortDescriptor) | |
order_by = string_or_sort_descriptor | |
end | |
end | |
request.setPredicate(pred) if pred | |
request.setFetchLimit(limit) if limit | |
request.sortDescriptors = [order_by] if order_by | |
fetch_error = Pointer.new_with_type('@') | |
results = self.moc.executeFetchRequest(request, error:fetch_error) | |
if ((fetch_error[0] != nil) || (results == nil)) | |
msg = (fetch_error[0].localizedDescription ? fetch_error[0].localizedDescription : "Unknown") | |
raise "Error fetching entity #{entity_name} because #{msg}" | |
end | |
return results | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment