motion_data_wrapper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ require 'motion_data_wrapper/version'
2
+
3
+ unless defined?(Motion::Project::Config)
4
+ raise "This file must be required within a RubyMotion project Rakefile."
5
+ end
6
+
7
+ Motion::Project::App.setup do |app|
8
+
9
+ # Load class definitions that require the following modules, these will get compiled after b/c we're using "unshift"
10
+ Dir[File.join(File.dirname(__FILE__), "motion_data_wrapper/*.rb")].each { |f| app.files.unshift(f) }
11
+
12
+ # Load in the modules
13
+ %w(errors model relation).each do |mod|
14
+ Dir[File.join(File.dirname(__FILE__), "motion_data_wrapper/#{mod}/**/*.rb")].each { |f| app.files.unshift(f) }
15
+ end
16
+
17
+ app.frameworks << "CoreData" unless app.frameworks.include?("CoreData")
18
+ end
@@ -0,0 +1,52 @@
1
+ module MotionDataWrapper
2
+ module Delegate
3
+
4
+ def managedObjectContext
5
+ @managedObjectContext ||= begin
6
+ documentsDirectory = NSFileManager.defaultManager.URLsForDirectory(NSDocumentDirectory, inDomains:NSUserDomainMask).lastObject;
7
+ storeURL = documentsDirectory.URLByAppendingPathComponent("#{sqlite_store_name}.sqlite")
8
+
9
+ error_ptr = Pointer.new(:object)
10
+ unless persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration:nil, URL:storeURL, options:persistent_store_options, error:error_ptr)
11
+ raise "Can't add persistent SQLite store: #{error_ptr[0].description}"
12
+ end
13
+
14
+ context = NSManagedObjectContext.alloc.init
15
+ context.persistentStoreCoordinator = persistentStoreCoordinator
16
+
17
+ context
18
+ end
19
+ end
20
+
21
+ def managedObjectModel
22
+ @managedObjectModel ||= begin
23
+ model = NSManagedObjectModel.mergedModelFromBundles([NSBundle.mainBundle]).mutableCopy
24
+
25
+ model.entities.each do |entity|
26
+ begin
27
+ Kernel.const_get(entity.name)
28
+ entity.setManagedObjectClassName(entity.name)
29
+
30
+ rescue NameError
31
+ entity.setManagedObjectClassName("Model")
32
+ end
33
+ end
34
+
35
+ model
36
+ end
37
+ end
38
+
39
+ def persistentStoreCoordinator
40
+ @coordinator ||= NSPersistentStoreCoordinator.alloc.initWithManagedObjectModel(managedObjectModel)
41
+ end
42
+
43
+ def sqlite_store_name
44
+ NSBundle.mainBundle.infoDictionary.objectForKey("CFBundleName")
45
+ end
46
+
47
+ def persistent_store_options
48
+ nil
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,11 @@
1
+ module MotionDataWrapper
2
+ class RecordInvalid < StandardError
3
+
4
+ def initialize(record)
5
+ @record = record
6
+ @errors = @record.errors
7
+ super(@errors.map { |k,v| "#{k} #{v}"}.join(', '))
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module MotionDataWrapper
2
+ class RecordNotFound < StandardError
3
+
4
+ def initialize(klass, id)
5
+ @klass = klass
6
+ @id = id
7
+ super("Could not find #{@klass.name} id: #{@id}")
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module MotionDataWrapper
2
+ class RecordNotSaved < StandardError
3
+
4
+ def initialize(record)
5
+ @record = record
6
+ @errors = @record.errors
7
+ super(@errors.map { |k,v| "#{k} #{v}"}.join(', '))
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module MotionDataWrapper
2
+ class Model < NSManagedObject
3
+ include CoreData
4
+ include FinderMethods
5
+ include Persistence
6
+ include Validations
7
+
8
+ def inspect
9
+ properties = []
10
+ entity.properties.select { |p| p.is_a?(NSAttributeDescription) }.each do |property|
11
+ properties << "#{property.name}: #{valueForKey(property.name).inspect}"
12
+ end
13
+
14
+ "#<#{entity.name} #{properties.join(", ")}>"
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ module MotionDataWrapper
2
+ class Model < NSManagedObject
3
+ module CoreData
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ def entity_description
12
+ @_metadata ||= UIApplication.sharedApplication.delegate.managedObjectModel.entitiesByName[name]
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,107 @@
1
+ module MotionDataWrapper
2
+ class Model < NSManagedObject
3
+ module FinderMethods
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ def all
12
+ relation.to_a
13
+ end
14
+
15
+ def count
16
+ relation.count
17
+ end
18
+
19
+ def destroy_all
20
+ all.map &:destroy
21
+ end
22
+
23
+ def except(query_part)
24
+ relation.except(query_part)
25
+ end
26
+
27
+ def find(object_id)
28
+ raise MotionDataWrapper::RecordNotFound.new(self, object_id) unless entity = find_by_id(object_id)
29
+ entity
30
+ end
31
+
32
+ def first
33
+ relation.first
34
+ end
35
+
36
+ def first!
37
+ first or raise MotionDataWrapper::RecordNotFound
38
+ end
39
+
40
+ def last
41
+ relation.last
42
+ end
43
+
44
+ def last!
45
+ last or raise MotionDataWrapper::RecordNotFound
46
+ end
47
+
48
+ def limit(l)
49
+ relation.limit(l)
50
+ end
51
+
52
+ def method_missing(method, *args, &block)
53
+ if method.start_with?("find_by_")
54
+ attribute = method.gsub("find_by_", "")
55
+ relation.where("#{attribute} = ?", *args).first
56
+ elsif method.start_with?("find_all_by_")
57
+ attribute = method.gsub("find_all_by_", "")
58
+ relation.where("#{attribute} = ?", *args).to_a
59
+ else
60
+ super
61
+ end
62
+ end
63
+
64
+ def offset(o)
65
+ relation.offset(o)
66
+ end
67
+
68
+ def order(*args)
69
+ relation.order(*args)
70
+ end
71
+
72
+ def pluck(column)
73
+ relation.pluck(column)
74
+ end
75
+
76
+ def reorder(*args)
77
+ relation.except(:order).order(*args)
78
+ end
79
+
80
+ def respond_to?(method)
81
+ if method.start_with?("find_by_") || method.start_with?("find_all_by_")
82
+ true
83
+ else
84
+ super
85
+ end
86
+ end
87
+
88
+ def uniq
89
+ relation.uniq
90
+ end
91
+
92
+ def where(*args)
93
+ relation.where(*args)
94
+ end
95
+
96
+ private
97
+
98
+ def relation
99
+ Relation.alloc.initWithClass(self)
100
+ end
101
+
102
+ end
103
+
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,85 @@
1
+ module MotionDataWrapper
2
+ class Model < NSManagedObject
3
+ module Persistence
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ def create(attributes={})
12
+ begin
13
+ model = create!(attributes)
14
+ rescue MotionDataWrapper::RecordNotSaved
15
+ end
16
+ model
17
+ end
18
+
19
+ def create!(attributes={})
20
+ model = new(attributes)
21
+ model.save!
22
+ model
23
+ end
24
+
25
+ def new(attributes={})
26
+ alloc.initWithEntity(entity_description, insertIntoManagedObjectContext:nil).tap do |model|
27
+ model.instance_variable_set('@new_record', true)
28
+ attributes.each do |keyPath, value|
29
+ model.setValue(value, forKey:keyPath)
30
+ end
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ def destroy
37
+
38
+ if context = managedObjectContext
39
+ context.deleteObject(self)
40
+ error = Pointer.new(:object)
41
+ context.save(error)
42
+ end
43
+
44
+ @destroyed = true
45
+ freeze
46
+ end
47
+
48
+ def destroyed?
49
+ @destroyed || false
50
+ end
51
+
52
+ def new_record?
53
+ @new_record || false
54
+ end
55
+
56
+ def persisted?
57
+ !(new_record? || destroyed?)
58
+ end
59
+
60
+ def save
61
+ begin
62
+ save!
63
+ rescue MotionDataWrapper::RecordNotSaved
64
+ return false
65
+ end
66
+ true
67
+ end
68
+
69
+ def save!
70
+ unless context = managedObjectContext
71
+ context = UIApplication.sharedApplication.delegate.managedObjectContext
72
+ context.insertObject(self)
73
+ end
74
+
75
+ error = Pointer.new(:object)
76
+ unless context.save(error)
77
+ managedObjectContext.deleteObject(self)
78
+ raise MotionDataWrapper::RecordNotSaved, self and return false
79
+ end
80
+ true
81
+ end
82
+
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,65 @@
1
+ module MotionDataWrapper
2
+ class Model < NSManagedObject
3
+ module Validations
4
+
5
+ def valid?
6
+ error_ptr = Pointer.new(:object)
7
+ v = new_record? ? validateForInsert(error_ptr) : validateForUpdate(error_ptr)
8
+ yield(v, error_ptr[0]) if block_given?
9
+ v
10
+ end
11
+
12
+ def errors
13
+ errors = {}
14
+ valid? do |valid, error|
15
+ next if error.nil?
16
+ if error.code == NSValidationMultipleErrorsError
17
+ errs = error.userInfo[NSDetailedErrorsKey]
18
+ errs.each do |nserr|
19
+ property = nserr.userInfo['NSValidationErrorKey']
20
+ errors[property] = message_for_error_code(nserr.code, property)
21
+ end
22
+ else
23
+ property = error.userInfo['NSValidationErrorKey']
24
+ errors[property] = message_for_error_code(error.code, property)
25
+ end
26
+ end
27
+ errors
28
+ end
29
+
30
+ private
31
+ def message_for_error_code(c, prop)
32
+ message = case c
33
+ when NSValidationMissingMandatoryPropertyError
34
+ "can't be blank"
35
+ when NSValidationNumberTooLargeError
36
+ "too large"
37
+ when NSValidationNumberTooSmallError
38
+ "too small"
39
+ when NSValidationDateTooLateError
40
+ "too late"
41
+ when NSValidationDateTooSoonError
42
+ "too soon"
43
+ when NSValidationInvalidDateError
44
+ "invalid date"
45
+ when NSValidationStringTooLongError
46
+ "too long"
47
+ when NSValidationStringTooShortError
48
+ "too short"
49
+ when NSValidationStringPatternMatchingError
50
+ "incorrect pattern"
51
+ when NSValidationRelationshipExceedsMaximumCountError
52
+ "too many"
53
+ when NSValidationRelationshipLacksMinimumCountError
54
+ "too few"
55
+ when NSValidationRelationshipDeniedDeleteError
56
+ "can't delete"
57
+ when NSManagedObjectValidationError
58
+ warnings = entity.propertiesByName[prop].validationWarnings rescue []
59
+ warnings.empty? ? "invalid" : warnings.join(', ')
60
+ end
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,12 @@
1
+ module MotionDataWrapper
2
+ class Relation < NSFetchRequest
3
+ include CoreData
4
+ include FinderMethods
5
+
6
+ def initWithClass(klass)
7
+ self.entity = klass.entity_description if init
8
+ self
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ module MotionDataWrapper
2
+ class Relation < NSFetchRequest
3
+ module CoreData
4
+
5
+ def inspect
6
+ to_a
7
+ end
8
+
9
+ def to_a
10
+ error_ptr = Pointer.new(:object)
11
+ context.executeFetchRequest(self, error:error_ptr)
12
+ end
13
+
14
+ private
15
+ def context
16
+ UIApplication.sharedApplication.delegate.managedObjectContext
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,97 @@
1
+ module MotionDataWrapper
2
+ class Relation < NSFetchRequest
3
+ module FinderMethods
4
+
5
+ def all
6
+ to_a
7
+ end
8
+
9
+ def count
10
+ return to_a.count if fetchOffset > 0
11
+ old_result_type = self.resultType
12
+ self.resultType = NSCountResultType
13
+ count = to_a[0]
14
+ self.resultType = old_result_type
15
+ return count
16
+ end
17
+
18
+ def destroy_all
19
+ all.map &:destroy
20
+ end
21
+
22
+ def except(query_part)
23
+ case query_part.to_sym
24
+ when :where
25
+ self.predicate = nil
26
+ when :order
27
+ self.sortDescriptors = nil
28
+ when :limit
29
+ self.fetchLimit = 0
30
+ else
31
+ raise ArgumentError, "unsupport query part '#{query_part}'"
32
+ end
33
+ self
34
+ end
35
+
36
+ def first
37
+ self.fetchLimit = 1
38
+ to_a[0]
39
+ end
40
+
41
+ def last
42
+ self.fetchOffset = self.count - 1 unless self.count < 1
43
+ self.fetchLimit = 1
44
+ to_a[0]
45
+ end
46
+
47
+ def limit(l)
48
+ l = l.to_i
49
+ raise ArgumentError, "limit '#{l}' cannot be less than zero. Use zero for no limit." if l < 0
50
+ self.fetchLimit = l
51
+ self
52
+ end
53
+
54
+ def offset(o)
55
+ o = o.to_i
56
+ raise ArgumentError, "offset '#{o}' cannot be less than zero." if o < 0
57
+ self.fetchOffset = o
58
+ self
59
+ end
60
+
61
+ def order(column, opts={})
62
+ descriptors = sortDescriptors.nil? ? [] : sortDescriptors.mutableCopy
63
+ descriptors << NSSortDescriptor.sortDescriptorWithKey(column.to_s, ascending:opts.fetch(:ascending, true))
64
+ self.sortDescriptors = descriptors
65
+ self
66
+ end
67
+
68
+ def pluck(column)
69
+ self.resultType = NSDictionaryResultType
70
+
71
+ attribute_description = entity.attributesByName[column]
72
+ raise ArgumentError, "#{column} not a valid column name" if attribute_description.nil?
73
+
74
+ self.propertiesToFetch = [attribute_description]
75
+ to_a.collect { |r| r[column] }
76
+ end
77
+
78
+ def uniq
79
+ self.returnsDistinctResults = true
80
+ self
81
+ end
82
+
83
+ def where(format, *args)
84
+ new_predicate = NSPredicate.predicateWithFormat(format.gsub("?", "%@"), argumentArray:args)
85
+
86
+ if self.predicate
87
+ self.predicate = NSCompoundPredicate.andPredicateWithSubpredicates([predicate, new_predicate])
88
+ else
89
+ self.predicate = new_predicate
90
+ end
91
+
92
+ self
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,3 @@
1
+ module MotionDataWrapper
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: motion_data_wrapper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matt Brewer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-23 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Forked from the mattgreen/nitron gem, this provides an intuitive way
15
+ to query and persist data in CoreData, while letting you use the powerful Xcode
16
+ data modeler and versioning tools for schema definitions.
17
+ email:
18
+ - matt.brewer@me.com
19
+ executables: []
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - lib/motion_data_wrapper.rb
24
+ - lib/motion_data_wrapper/delegate.rb
25
+ - lib/motion_data_wrapper/errors/record_invalid.rb
26
+ - lib/motion_data_wrapper/errors/record_not_found.rb
27
+ - lib/motion_data_wrapper/errors/record_not_saved.rb
28
+ - lib/motion_data_wrapper/model.rb
29
+ - lib/motion_data_wrapper/model/core_data.rb
30
+ - lib/motion_data_wrapper/model/finder_methods.rb
31
+ - lib/motion_data_wrapper/model/persistence.rb
32
+ - lib/motion_data_wrapper/model/validations.rb
33
+ - lib/motion_data_wrapper/relation.rb
34
+ - lib/motion_data_wrapper/relation/core_data.rb
35
+ - lib/motion_data_wrapper/relation/finder_methods.rb
36
+ - lib/motion_data_wrapper/version.rb
37
+ homepage: https://github.com/macfanatic/motion_data_wrapper
38
+ licenses: []
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubyforge_project:
57
+ rubygems_version: 1.8.24
58
+ signing_key:
59
+ specification_version: 3
60
+ summary: Provides an easy ActiveRecord-like interface to CoreData
61
+ test_files: []
62
+ has_rdoc: