motion_data_wrapper 0.0.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.
@@ -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: