motion_migrate 0.1.0
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.
- data/.gitignore +17 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +152 -0
- data/Rakefile +3 -0
- data/lib/motion_migrate/generate.rb +51 -0
- data/lib/motion_migrate/model.rb +10 -0
- data/lib/motion_migrate/motion_generate/entity.rb +15 -0
- data/lib/motion_migrate/motion_generate/io.rb +79 -0
- data/lib/motion_migrate/motion_generate/parser.rb +27 -0
- data/lib/motion_migrate/motion_generate/property.rb +171 -0
- data/lib/motion_migrate/motion_generate/relationship.rb +153 -0
- data/lib/motion_migrate/motion_model/property.rb +14 -0
- data/lib/motion_migrate/motion_model/relationship.rb +20 -0
- data/lib/motion_migrate.rb +20 -0
- data/lib/tasks/migrate.rake +53 -0
- data/lib/version.rb +3 -0
- data/motion_migrate.gemspec +21 -0
- data/spec/property_spec.rb +113 -0
- data/spec/relationship_spec.rb +54 -0
- data/spec_project/.gitignore +18 -0
- data/spec_project/Gemfile +6 -0
- data/spec_project/Rakefile +14 -0
- data/spec_project/app/app_delegate.rb +7 -0
- data/spec_project/app/models/pilot.rb +7 -0
- data/spec_project/app/models/plane.rb +11 -0
- data/spec_project/db/schema.xcdatamodeld/.xccurrentversion +8 -0
- data/spec_project/db/schema.xcdatamodeld/schema.1.xcdatamodel/contents +6 -0
- data/spec_project/db/schema.xcdatamodeld/schema.10.xcdatamodel/contents +18 -0
- data/spec_project/db/schema.xcdatamodeld/schema.2.xcdatamodel/contents +7 -0
- data/spec_project/db/schema.xcdatamodeld/schema.3.xcdatamodel/contents +7 -0
- data/spec_project/db/schema.xcdatamodeld/schema.4.xcdatamodel/contents +8 -0
- data/spec_project/db/schema.xcdatamodeld/schema.5.xcdatamodel/contents +9 -0
- data/spec_project/db/schema.xcdatamodeld/schema.6.xcdatamodel/contents +13 -0
- data/spec_project/db/schema.xcdatamodeld/schema.7.xcdatamodel/contents +14 -0
- data/spec_project/db/schema.xcdatamodeld/schema.8.xcdatamodel/contents +16 -0
- data/spec_project/db/schema.xcdatamodeld/schema.9.xcdatamodel/contents +16 -0
- data/spec_project/spec/helper.rb +8 -0
- data/spec_project/spec/property_spec.rb +57 -0
- data/spec_project/spec/relationship_spec.rb +105 -0
- data/spec_project/vendor/Podfile.lock +11 -0
- metadata +113 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
module MotionMigrate
|
|
2
|
+
module MotionGenerate
|
|
3
|
+
module Relationship
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.extend(ClassMethods)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
def belongs_to(name, options={})
|
|
10
|
+
relationship(name, :belongs_to, options)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def has_many(name, options={})
|
|
14
|
+
relationship(name, :has_many, options)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def relationship(name, type, options={})
|
|
18
|
+
options.each { |key, value| raise_if_relationship_option_not_allowed(type, key) }
|
|
19
|
+
|
|
20
|
+
raise_if_relationship_options_missing(options)
|
|
21
|
+
raise_if_deletion_rule_not_allowed(options)
|
|
22
|
+
|
|
23
|
+
attributes = {
|
|
24
|
+
name: name,
|
|
25
|
+
optional: core_data_boolean(true),
|
|
26
|
+
deletionRule: core_data_string(:no_action),
|
|
27
|
+
syncable: core_data_boolean(true)
|
|
28
|
+
}
|
|
29
|
+
attributes.merge!({ minCount: 1, maxCount: 1 }) if type == :belongs_to
|
|
30
|
+
attributes.merge!(core_data_relationship_attributes(type, options))
|
|
31
|
+
relationships[self.entity_name] = {} if relationships[self.entity_name].nil?
|
|
32
|
+
relationships[self.entity_name][name] = attributes
|
|
33
|
+
attributes
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def relationships
|
|
37
|
+
@@relationships ||= {}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def raise_if_relationship_option_not_allowed(type, option)
|
|
41
|
+
unless relationship_option_allowed?(type, option)
|
|
42
|
+
raise <<-ERROR
|
|
43
|
+
! The option must be one of the following:
|
|
44
|
+
!
|
|
45
|
+
! For type :belongs_to:
|
|
46
|
+
! :required
|
|
47
|
+
! :deletion_rule
|
|
48
|
+
! :class_name
|
|
49
|
+
! :inverse_of
|
|
50
|
+
! :spotlight
|
|
51
|
+
! :truth_file
|
|
52
|
+
! :transient
|
|
53
|
+
!
|
|
54
|
+
! For type :has_many:
|
|
55
|
+
! :required
|
|
56
|
+
! :min
|
|
57
|
+
! :max
|
|
58
|
+
! :deletion_rule
|
|
59
|
+
! :class_name
|
|
60
|
+
! :inverse_of
|
|
61
|
+
! :ordered
|
|
62
|
+
! :spotlight
|
|
63
|
+
! :truth_file
|
|
64
|
+
! :transient
|
|
65
|
+
ERROR
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def raise_if_relationship_options_missing(options)
|
|
70
|
+
unless relationship_options_complete?(options)
|
|
71
|
+
raise <<-ERROR
|
|
72
|
+
! One of these options are required:
|
|
73
|
+
! :class_name
|
|
74
|
+
! :inverse_of
|
|
75
|
+
ERROR
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def deletion_rule_allowed?(options)
|
|
80
|
+
allowed_deletion_rules = [
|
|
81
|
+
:nullify,
|
|
82
|
+
:cascade,
|
|
83
|
+
:deny
|
|
84
|
+
]
|
|
85
|
+
!options[:deletion_rule] || allowed_deletion_rules.include?(options[:deletion_rule])
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def raise_if_deletion_rule_not_allowed(options)
|
|
89
|
+
unless deletion_rule_allowed?(options)
|
|
90
|
+
raise <<-ERROR
|
|
91
|
+
! One of these deletion rules are allowed:
|
|
92
|
+
! :nullify
|
|
93
|
+
! :cascade
|
|
94
|
+
! :deny
|
|
95
|
+
ERROR
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def relationship_options_complete?(options)
|
|
100
|
+
required_options = [:class_name, :inverse_of]
|
|
101
|
+
(required_options.uniq - options.keys.uniq).empty?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def relationship_option_allowed?(type, option)
|
|
105
|
+
allowed_options = {
|
|
106
|
+
has_many: [:ordered, :min, :max],
|
|
107
|
+
}[type] || []
|
|
108
|
+
|
|
109
|
+
allowed_options += [
|
|
110
|
+
:required,
|
|
111
|
+
:spotlight,
|
|
112
|
+
:truth_file,
|
|
113
|
+
:transient,
|
|
114
|
+
:inverse_of,
|
|
115
|
+
:class_name,
|
|
116
|
+
:deletion_rule
|
|
117
|
+
]
|
|
118
|
+
allowed_options.include?(option)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def core_data_relationship_attributes(type, options)
|
|
122
|
+
attributes = {}
|
|
123
|
+
|
|
124
|
+
options.each do |key, value|
|
|
125
|
+
case key
|
|
126
|
+
when :required
|
|
127
|
+
attributes[:optional] = core_data_boolean(value != true)
|
|
128
|
+
when :inverse_of
|
|
129
|
+
attributes[:inverseName] = value
|
|
130
|
+
when :class_name
|
|
131
|
+
attributes[:inverseEntity] = value
|
|
132
|
+
attributes[:destinationEntity] = value
|
|
133
|
+
when :deletion_rule
|
|
134
|
+
attributes[:deletionRule] = core_data_string(value)
|
|
135
|
+
when :transient
|
|
136
|
+
attributes[:transient] = core_data_boolean(value)
|
|
137
|
+
when :spotlight
|
|
138
|
+
attributes[:spotlightIndexingEnabled] = core_data_boolean(value)
|
|
139
|
+
when :truth_file
|
|
140
|
+
attributes[:storedInTruthFile] = core_data_boolean(value)
|
|
141
|
+
when :min
|
|
142
|
+
attributes[:minCount] = value
|
|
143
|
+
when :max
|
|
144
|
+
attributes[:maxCount] = value
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
attributes[:toMany] = core_data_boolean(type == :has_many)
|
|
148
|
+
attributes
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module MotionMigrate
|
|
2
|
+
module MotionModel
|
|
3
|
+
module Relationship
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.extend(ClassMethods)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
def belongs_to(name, options={})
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def has_many(name, options={})
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def belongs_to(name, options={})
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
unless defined?(Motion::Project::Config)
|
|
2
|
+
raise "This file must be required within a RubyMotion project Rakefile."
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
Motion::Project::App.setup do |app|
|
|
6
|
+
Dir.glob(File.join(File.dirname(__FILE__), "motion_migrate/motion_model/**/*.rb")).each do |file|
|
|
7
|
+
app.files.unshift(file)
|
|
8
|
+
end
|
|
9
|
+
app.files.unshift(File.join(File.dirname(__FILE__), 'motion_migrate/model.rb'))
|
|
10
|
+
|
|
11
|
+
app.frameworks += ['CoreData'] unless app.frameworks.include?("CoreData")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module MotionMigrate
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Include rake files
|
|
18
|
+
Dir.glob(File.join(File.dirname(__FILE__), "tasks/**/*.rake")) do |task|
|
|
19
|
+
import task
|
|
20
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require "nokogiri"
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
|
|
4
|
+
require "motion_migrate/motion_generate/entity"
|
|
5
|
+
require "motion_migrate/motion_generate/parser"
|
|
6
|
+
require "motion_migrate/motion_generate/property"
|
|
7
|
+
require "motion_migrate/motion_generate/relationship"
|
|
8
|
+
require "motion_migrate/generate"
|
|
9
|
+
require "motion_migrate/motion_generate/io"
|
|
10
|
+
|
|
11
|
+
namespace :db do
|
|
12
|
+
desc "Generate a version of the current database model as described in the models."
|
|
13
|
+
task :migrate do
|
|
14
|
+
schema_xml = MotionMigrate::Generate.build
|
|
15
|
+
MotionMigrate::IO.write(schema_xml)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc "Go back to the previous version of the database model."
|
|
19
|
+
task :rollback do
|
|
20
|
+
if version = MotionMigrate::IO.current_schema_version
|
|
21
|
+
if version == 1
|
|
22
|
+
puts "! Can't rollback schema when version is 1."
|
|
23
|
+
else
|
|
24
|
+
schema = MotionMigrate::IO.current_schema
|
|
25
|
+
MotionMigrate::IO.write_current_schema(version - 1)
|
|
26
|
+
FileUtils.rm_rf(schema)
|
|
27
|
+
puts "# Data model rolled back to version #{version - 1}."
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
puts "! No schema found in this project."
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
namespace :schema do
|
|
35
|
+
desc "Dump the current version of the database model scheme."
|
|
36
|
+
task :dump do
|
|
37
|
+
if current_schema = MotionMigrate::IO.current_schema
|
|
38
|
+
puts File.open(File.join(current_schema, "contents")).read
|
|
39
|
+
else
|
|
40
|
+
puts "! No schema found in this project."
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
desc "Show the current version of the database model scheme."
|
|
45
|
+
task :version do
|
|
46
|
+
if version = MotionMigrate::IO.current_schema_version
|
|
47
|
+
puts "# Data model is currently at version #{version}."
|
|
48
|
+
else
|
|
49
|
+
puts "! No schema found in this project."
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/version.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |gem|
|
|
7
|
+
gem.name = "motion_migrate"
|
|
8
|
+
gem.version = MotionMigrate::VERSION
|
|
9
|
+
gem.authors = ["Jelle Vandebeeck"]
|
|
10
|
+
gem.email = ["jelle@fousa.be"]
|
|
11
|
+
gem.description = %q{Generate the Core Data model from your RubyMotion code.}
|
|
12
|
+
gem.summary = %q{Generate the Core Data model from your RubyMotion code. Never open XCode again!}
|
|
13
|
+
gem.homepage = "http://fousa.github.com/motion_migrate/"
|
|
14
|
+
|
|
15
|
+
gem.files = `git ls-files`.split($/)
|
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
17
|
+
gem.require_paths = ["lib"]
|
|
18
|
+
|
|
19
|
+
gem.add_development_dependency 'rake'
|
|
20
|
+
gem.add_dependency 'nokogiri'
|
|
21
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
|
|
3
|
+
require "motion_migrate/motion_generate/entity"
|
|
4
|
+
require "motion_migrate/motion_generate/parser"
|
|
5
|
+
require "motion_migrate/motion_generate/property"
|
|
6
|
+
require "motion_migrate/motion_generate/relationship"
|
|
7
|
+
require "motion_migrate/generate"
|
|
8
|
+
|
|
9
|
+
module MotionMigrate
|
|
10
|
+
describe "property definitions in the model" do
|
|
11
|
+
before do
|
|
12
|
+
@allowed_options = {
|
|
13
|
+
required: true,
|
|
14
|
+
transient: true,
|
|
15
|
+
indexed: true,
|
|
16
|
+
spotlight: true,
|
|
17
|
+
truth_file: true
|
|
18
|
+
}
|
|
19
|
+
@filled_allowed_attributes = {
|
|
20
|
+
optional: "NO",
|
|
21
|
+
transient: "YES",
|
|
22
|
+
indexed: "YES",
|
|
23
|
+
spotlightIndexingEnabled: "YES",
|
|
24
|
+
storedInTruthFile: "YES",
|
|
25
|
+
syncable: "YES"
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
%w(string integer_16 integer_32 integer_64 decimal double float date binary_data boolean).each do |type|
|
|
30
|
+
it "should be able to define #{type}" do
|
|
31
|
+
type_string = type.split("_").each{|word| word.capitalize! }.join(" ")
|
|
32
|
+
type_string = "Binary" if type == "binary_data"
|
|
33
|
+
MotionMigrate::Model.property(:field, type).should == { :name => :field,
|
|
34
|
+
:attributeType => type_string,
|
|
35
|
+
:optional=>"YES",
|
|
36
|
+
:syncable => "YES" }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should error on undiffened types" do
|
|
41
|
+
lambda { MotionMigrate::Model.property(:field, :unknown) }.should raise_error
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
%w(string integer_16 integer_32 integer_64 decimal double float date binary_data boolean).each do |type|
|
|
45
|
+
it "should error on undiffened options for #{type}" do
|
|
46
|
+
lambda { MotionMigrate::Model.property(:field, type, :unknown => true) }.should raise_error
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should return the correct options for string" do
|
|
51
|
+
options = @allowed_options.merge({
|
|
52
|
+
min: "1",
|
|
53
|
+
max: "10",
|
|
54
|
+
default: "motion",
|
|
55
|
+
regex: "/we/"
|
|
56
|
+
})
|
|
57
|
+
MotionMigrate::Model.property(:field, :string, options).should == @filled_allowed_attributes.merge({ :name => :field,
|
|
58
|
+
:attributeType => "String",
|
|
59
|
+
:minValueString => "1",
|
|
60
|
+
:maxValueString => "10",
|
|
61
|
+
:defaultValueString => "motion",
|
|
62
|
+
:regularExpressionString => "/we/" })
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
%w(integer_16 integer_32 integer_64 decimal double float).each do |type|
|
|
66
|
+
it "should return the correct options for #{type}" do
|
|
67
|
+
options = @allowed_options.merge({
|
|
68
|
+
min: "1",
|
|
69
|
+
max: "10",
|
|
70
|
+
default: "5"
|
|
71
|
+
})
|
|
72
|
+
MotionMigrate::Model.property(:field, type, options).should == @filled_allowed_attributes.merge({ :name => :field,
|
|
73
|
+
:attributeType => type.split("_").each{|word| word.capitalize! }.join(" "),
|
|
74
|
+
:minValueString => "1",
|
|
75
|
+
:maxValueString => "10",
|
|
76
|
+
:defaultValueString => "5" })
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should return the correct options for boolean" do
|
|
81
|
+
options = @allowed_options.merge({
|
|
82
|
+
default: true
|
|
83
|
+
})
|
|
84
|
+
MotionMigrate::Model.property(:field, :boolean, options).should == @filled_allowed_attributes.merge({ :name => :field,
|
|
85
|
+
:attributeType => "Boolean",
|
|
86
|
+
:defaultValueString => "YES" })
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "should return the correct options for binary_data" do
|
|
90
|
+
options = @allowed_options.merge({
|
|
91
|
+
external_storage: true
|
|
92
|
+
})
|
|
93
|
+
MotionMigrate::Model.property(:field, :binary_data, options).should == @filled_allowed_attributes.merge({ :name => :field,
|
|
94
|
+
:attributeType => "Binary",
|
|
95
|
+
:allowsExternalBinaryDataStorage => "YES" })
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "should return the correct options for date" do
|
|
99
|
+
options = @allowed_options.merge({
|
|
100
|
+
min: DateTime.new(2013, 1, 1, 12, 0, 0),
|
|
101
|
+
max: DateTime.new(2013, 1, 31, 12, 0, 0),
|
|
102
|
+
default: DateTime.new(2013, 1, 5, 12, 0, 0)
|
|
103
|
+
})
|
|
104
|
+
MotionMigrate::Model.property(:field, :date, options).should == @filled_allowed_attributes.merge({ :name => :field,
|
|
105
|
+
:attributeType => "Date",
|
|
106
|
+
:minDateTimeInterval => "378738000",
|
|
107
|
+
:maxDateTimeInterval => "381330000",
|
|
108
|
+
:defaultDateTimeInterval => "379083600" })
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Test all types + properties
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require "motion_migrate/motion_generate/entity"
|
|
2
|
+
require "motion_migrate/motion_generate/parser"
|
|
3
|
+
require "motion_migrate/motion_generate/property"
|
|
4
|
+
require "motion_migrate/motion_generate/relationship"
|
|
5
|
+
require "motion_migrate/generate"
|
|
6
|
+
|
|
7
|
+
module MotionMigrate
|
|
8
|
+
describe "relationship definitions in the model" do
|
|
9
|
+
before do
|
|
10
|
+
@allowed_options = {
|
|
11
|
+
required: true,
|
|
12
|
+
transient: true,
|
|
13
|
+
class_name: "Test",
|
|
14
|
+
inverse_of: "test",
|
|
15
|
+
deletion_rule: :cascade,
|
|
16
|
+
spotlight: true,
|
|
17
|
+
truth_file: true
|
|
18
|
+
}
|
|
19
|
+
@filled_allowed_attributes = {
|
|
20
|
+
optional: "NO",
|
|
21
|
+
transient: "YES",
|
|
22
|
+
inverseEntity: "Test",
|
|
23
|
+
destinationEntity: "Test",
|
|
24
|
+
inverseName: "test",
|
|
25
|
+
deletionRule: "Cascade",
|
|
26
|
+
spotlightIndexingEnabled: "YES",
|
|
27
|
+
storedInTruthFile: "YES",
|
|
28
|
+
syncable: "YES"
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
%w(belongs_to has_many).each do |type|
|
|
33
|
+
it "should error on incomplete options for #{type}" do
|
|
34
|
+
lambda { MotionMigrate::Model.send(type, :field) }.should raise_error
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should error on undiffened options for #{type}" do
|
|
38
|
+
lambda { MotionMigrate::Model.send(type, :field, :class_name => "Test", :inverse_of => "test", :unknown => true) }.should raise_error
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should error on undiffened deletion rules for #{type}" do
|
|
42
|
+
lambda { MotionMigrate::Model.send(type, :field, :class_name => "Test", :inverse_of => "test", :deletion_rule => :unknown) }.should raise_error
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should return the correct options for belongs_to" do
|
|
47
|
+
MotionMigrate::Model.belongs_to(:field, @allowed_options).should == @filled_allowed_attributes.merge({ :toMany => "NO", :name => :field, :minCount => 1, :maxCount => 1 })
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should return the correct options for has_many" do
|
|
51
|
+
MotionMigrate::Model.has_many(:field, @allowed_options).should == @filled_allowed_attributes.merge({ :toMany => "YES", :name => :field })
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
$:.unshift("/Library/RubyMotion/lib")
|
|
3
|
+
require 'motion/project'
|
|
4
|
+
|
|
5
|
+
require 'bundler'
|
|
6
|
+
Bundler.require
|
|
7
|
+
|
|
8
|
+
Motion::Project::App.setup do |app|
|
|
9
|
+
app.name = 'Motion Migrate Spec Project'
|
|
10
|
+
|
|
11
|
+
app.pods do
|
|
12
|
+
pod 'MagicalRecord', '2.1'
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
class Pilot < MotionMigrate::Model
|
|
2
|
+
property :name, :string
|
|
3
|
+
|
|
4
|
+
belongs_to :plane, :class_name => "Plane", :inverse_of => :pilot
|
|
5
|
+
has_many :owned_planes, :class_name => "Plane", :inverse_of => :owner
|
|
6
|
+
has_many :flown_planes, :class_name => "Plane", :inverse_of => :flown_by_pilots
|
|
7
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class Plane < MotionMigrate::Model
|
|
2
|
+
property :name, :string
|
|
3
|
+
property :multi_engine, :boolean, :default => false
|
|
4
|
+
property :first_flight_at, :date
|
|
5
|
+
property :flight_info, :binary_data
|
|
6
|
+
|
|
7
|
+
belongs_to :pilot, :class_name => "Pilot", :inverse_of => :plane
|
|
8
|
+
belongs_to :owner, :class_name => "Pilot", :inverse_of => :owned_planes
|
|
9
|
+
|
|
10
|
+
has_many :flown_by_pilots, :class_name => "Pilot", :inverse_of => :flown_planes
|
|
11
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>_XCCurrentVersionName</key>
|
|
6
|
+
<string>schema.10.xcdatamodel</string>
|
|
7
|
+
</dict>
|
|
8
|
+
</plist>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
|
3
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
|
5
|
+
</entity>
|
|
6
|
+
</model>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
|
3
|
+
<entity name="Pilot" representedClassName="Pilot" syncable="YES">
|
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
|
5
|
+
<relationship name="plane" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Plane" destinationEntity="Plane" inverseName="pilot" toMany="NO"/>
|
|
6
|
+
<relationship name="owned_planes" optional="YES" deletionRule="No Action" syncable="YES" inverseEntity="Plane" destinationEntity="Plane" inverseName="owner" toMany="YES"/>
|
|
7
|
+
<relationship name="flown_planes" optional="YES" deletionRule="No Action" syncable="YES" inverseEntity="Plane" destinationEntity="Plane" inverseName="flown_by_pilots" toMany="YES"/>
|
|
8
|
+
</entity>
|
|
9
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
|
10
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
|
11
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES" defaultValueString="NO"/>
|
|
12
|
+
<attribute name="first_flight_at" attributeType="Date" optional="YES" syncable="YES"/>
|
|
13
|
+
<attribute name="flight_info" attributeType="Binary" optional="YES" syncable="YES"/>
|
|
14
|
+
<relationship name="pilot" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Pilot" destinationEntity="Pilot" inverseName="plane" toMany="NO"/>
|
|
15
|
+
<relationship name="owner" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Pilot" destinationEntity="Pilot" inverseName="owned_planes" toMany="NO"/>
|
|
16
|
+
<relationship name="flown_by_pilots" optional="YES" deletionRule="No Action" syncable="YES" inverseEntity="Pilot" destinationEntity="Pilot" inverseName="flown_planes" toMany="YES"/>
|
|
17
|
+
</entity>
|
|
18
|
+
</model>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
|
3
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
|
5
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES"/>
|
|
6
|
+
</entity>
|
|
7
|
+
</model>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
|
3
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
|
5
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES" defaultValueString="NO"/>
|
|
6
|
+
</entity>
|
|
7
|
+
</model>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
|
3
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
|
5
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES" defaultValueString="NO"/>
|
|
6
|
+
<attribute name="first_flight_at" attributeType="Date" optional="YES" syncable="YES"/>
|
|
7
|
+
</entity>
|
|
8
|
+
</model>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
|
3
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
|
5
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES" defaultValueString="NO"/>
|
|
6
|
+
<attribute name="first_flight_at" attributeType="Date" optional="YES" syncable="YES"/>
|
|
7
|
+
<attribute name="flight_info" attributeType="Binary" optional="YES" syncable="YES"/>
|
|
8
|
+
</entity>
|
|
9
|
+
</model>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
|
3
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
|
5
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES" defaultValueString="NO"/>
|
|
6
|
+
<attribute name="first_flight_at" attributeType="Date" optional="YES" syncable="YES"/>
|
|
7
|
+
<attribute name="flight_info" attributeType="Binary" optional="YES" syncable="YES"/>
|
|
8
|
+
<relationship name="pilot" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Pilot" destinationEntity="Pilot" inverseName="plane" toMany="NO"/>
|
|
9
|
+
</entity>
|
|
10
|
+
<entity name="Pilot" representedClassName="Pilot" syncable="YES">
|
|
11
|
+
<relationship name="plane" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Plane" destinationEntity="Plane" inverseName="pilot" toMany="NO"/>
|
|
12
|
+
</entity>
|
|
13
|
+
</model>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
|
3
|
+
<entity name="Pilot" representedClassName="Pilot" syncable="YES">
|
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
|
5
|
+
<relationship name="plane" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Plane" destinationEntity="Plane" inverseName="pilot" toMany="NO"/>
|
|
6
|
+
</entity>
|
|
7
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
|
8
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
|
9
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES" defaultValueString="NO"/>
|
|
10
|
+
<attribute name="first_flight_at" attributeType="Date" optional="YES" syncable="YES"/>
|
|
11
|
+
<attribute name="flight_info" attributeType="Binary" optional="YES" syncable="YES"/>
|
|
12
|
+
<relationship name="pilot" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Pilot" destinationEntity="Pilot" inverseName="plane" toMany="NO"/>
|
|
13
|
+
</entity>
|
|
14
|
+
</model>
|