metamodel 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/metamodel.rb +2 -0
- data/lib/metamodel/command.rb +6 -2
- data/lib/metamodel/command/install.rb +52 -0
- data/lib/metamodel/config.rb +4 -0
- data/lib/metamodel/installer.rb +92 -0
- data/lib/metamodel/installer/renderer.rb +116 -0
- data/lib/metamodel/installer/validator.rb +55 -0
- data/lib/metamodel/metafile.rb +61 -0
- data/lib/metamodel/metafile/dsl.rb +44 -0
- data/lib/metamodel/record/association.rb +24 -30
- data/lib/metamodel/record/model.rb +7 -11
- data/lib/metamodel/record/property.rb +0 -4
- data/lib/metamodel/template/belongs_to_association.swift +29 -0
- data/lib/metamodel/template/has_many_association.swift +99 -0
- data/lib/metamodel/template/helper.swift +8 -6
- data/lib/metamodel/template/metamodel.swift +7 -0
- data/lib/metamodel/template/model_delete.swift +2 -5
- data/lib/metamodel/template/model_initialize.swift +6 -18
- data/lib/metamodel/template/model_query.swift +7 -3
- data/lib/metamodel/template/model_update.swift +2 -2
- data/lib/metamodel/template/static_methods.swift +1 -1
- data/lib/metamodel/template/table_initialize.swift +1 -1
- data/lib/metamodel/version.rb +1 -1
- metadata +11 -7
- data/lib/metamodel/command/build.rb +0 -148
- data/lib/metamodel/command/build/renderer.rb +0 -55
- data/lib/metamodel/command/build/resolver.rb +0 -72
- data/lib/metamodel/command/build/translator.rb +0 -66
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a027c62103e0c1e22308807cbb65e60921e2cfc3
|
4
|
+
data.tar.gz: ef725ae4f7bdfbbfd06b306523f127346ac1b44f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d68afdc7a74ed5c62a66f5ba85a071c1ffdee8a45e30b2d23fe581e4c2b4212c5db55a3de07e2f799ab8a08d18b036f490379da9926faaf6abb74c3d17cfa61
|
7
|
+
data.tar.gz: 83c413f52a8c1fe141424395862d9640311fc0cbc114b943f02f5463a134da0ddef7661217bc0a087201a62d240ba020cb3e635961039f418f71d4a5f3f7db57
|
data/lib/metamodel.rb
CHANGED
data/lib/metamodel/command.rb
CHANGED
@@ -5,7 +5,7 @@ module MetaModel
|
|
5
5
|
class Command < CLAide::Command
|
6
6
|
require 'metamodel/command/init'
|
7
7
|
require 'metamodel/command/generate'
|
8
|
-
require 'metamodel/command/
|
8
|
+
require 'metamodel/command/install'
|
9
9
|
require 'metamodel/command/clean'
|
10
10
|
|
11
11
|
include Config::Mixin
|
@@ -18,7 +18,7 @@ module MetaModel
|
|
18
18
|
|
19
19
|
METAMODEL_COMMAND_ALIAS = {
|
20
20
|
"g" => "generate",
|
21
|
-
"i" => "
|
21
|
+
"i" => "install",
|
22
22
|
"b" => "build",
|
23
23
|
"c" => "clean"
|
24
24
|
}
|
@@ -48,6 +48,10 @@ module MetaModel
|
|
48
48
|
super
|
49
49
|
end
|
50
50
|
|
51
|
+
def installer_for_config
|
52
|
+
Installer.new(config.metafile)
|
53
|
+
end
|
54
|
+
|
51
55
|
#-------------------------------------------------------------------------#
|
52
56
|
|
53
57
|
private
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'git'
|
2
|
+
|
3
|
+
module MetaModel
|
4
|
+
class Command
|
5
|
+
class Install < Command
|
6
|
+
include Config::Mixin
|
7
|
+
self.summary = "Build a MetaModel.framework from Metafile"
|
8
|
+
self.description = <<-DESC
|
9
|
+
Clone a metamodel project template from GitHub, parsing Metafile, validating models,
|
10
|
+
generate model swift file and build MetaModel.framework.
|
11
|
+
DESC
|
12
|
+
|
13
|
+
attr_accessor :models
|
14
|
+
|
15
|
+
def initialize(argv)
|
16
|
+
validate!
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
UI.section "Building MetaModel.framework in project" do
|
22
|
+
prepare
|
23
|
+
installer = installer_for_config
|
24
|
+
installer.install!
|
25
|
+
end
|
26
|
+
UI.notice "Please drag MetaModel.framework into Embedded Binaries phrase.\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
def prepare
|
30
|
+
clone_project
|
31
|
+
end
|
32
|
+
|
33
|
+
def clone_project
|
34
|
+
if File.exist? config.metamodel_xcode_project
|
35
|
+
UI.message "Existing project `#{config.metamodel_xcode_project}`"
|
36
|
+
else
|
37
|
+
UI.section "Cloning MetaModel project into `./metamodel` folder" do
|
38
|
+
Git.clone(config.metamodel_template_uri, 'metamodel', :depth => 1)
|
39
|
+
UI.message "Using `#{config.metamodel_xcode_project}` to build module"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def validate!
|
45
|
+
# super
|
46
|
+
raise Informative, 'No Metafile in current directory' unless config.metafile_in_dir(Pathname.pwd)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/metamodel/config.rb
CHANGED
@@ -0,0 +1,92 @@
|
|
1
|
+
module MetaModel
|
2
|
+
class Installer
|
3
|
+
require 'metamodel/installer/renderer'
|
4
|
+
require 'metamodel/installer/validator'
|
5
|
+
|
6
|
+
include Config::Mixin
|
7
|
+
|
8
|
+
attr_reader :metafile
|
9
|
+
|
10
|
+
attr_accessor :models
|
11
|
+
attr_accessor :associations
|
12
|
+
|
13
|
+
attr_accessor :current_model
|
14
|
+
|
15
|
+
def initialize(metafile)
|
16
|
+
@metafile = metafile
|
17
|
+
end
|
18
|
+
|
19
|
+
def install!
|
20
|
+
@models = metafile.models
|
21
|
+
@associations = metafile.associations
|
22
|
+
Renderer.new(@models, @associations).tap do |renderer|
|
23
|
+
renderer.render!
|
24
|
+
end
|
25
|
+
|
26
|
+
update_initialize_method
|
27
|
+
build_metamodel_framework unless config.skip_build?
|
28
|
+
end
|
29
|
+
|
30
|
+
def update_initialize_method
|
31
|
+
template = File.read File.expand_path(File.join(File.dirname(__FILE__), "./template/metamodel.swift"))
|
32
|
+
result = ErbalTemplate::render_from_hash(template, { :models => @models, :associations => @associations })
|
33
|
+
model_path = Pathname.new("./metamodel/MetaModel/MetaModel.swift")
|
34
|
+
File.write model_path, result
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_metamodel_framework
|
38
|
+
UI.section "Generating MetaModel.framework" do
|
39
|
+
build_framework_on_iphoneos
|
40
|
+
build_framework_on_iphonesimulator
|
41
|
+
copy_framework_swiftmodule_files
|
42
|
+
lipo_frameworks_on_different_archs
|
43
|
+
end
|
44
|
+
UI.message "-> ".green + "MetaModel.framework located in current folder"
|
45
|
+
end
|
46
|
+
|
47
|
+
def build_framework_on_iphoneos
|
48
|
+
build_iphoneos = "xcodebuild -scheme MetaModel \
|
49
|
+
-project MetaModel/MetaModel.xcodeproj \
|
50
|
+
-configuration Release -sdk iphoneos \
|
51
|
+
-derivedDataPath './metamodel' \
|
52
|
+
BITCODE_GENERATION_MODE=bitcode \
|
53
|
+
ONLY_ACTIVE_ARCH=NO \
|
54
|
+
CODE_SIGNING_REQUIRED=NO \
|
55
|
+
CODE_SIGN_IDENTITY= \
|
56
|
+
clean build"
|
57
|
+
result = system "#{build_iphoneos} > /dev/null"
|
58
|
+
raise Informative, 'Building framework on iphoneos failed.' unless result
|
59
|
+
end
|
60
|
+
|
61
|
+
def build_framework_on_iphonesimulator
|
62
|
+
build_iphonesimulator = "xcodebuild -scheme MetaModel \
|
63
|
+
-project MetaModel/MetaModel.xcodeproj \
|
64
|
+
-configuration Release -sdk iphonesimulator \
|
65
|
+
-derivedDataPath './metamodel' \
|
66
|
+
ONLY_ACTIVE_ARCH=NO \
|
67
|
+
CODE_SIGNING_REQUIRED=NO \
|
68
|
+
CODE_SIGN_IDENTITY= \
|
69
|
+
clean build"
|
70
|
+
result = system "#{build_iphonesimulator} > /dev/null"
|
71
|
+
raise Informative, 'Building framework on iphonesimulator failed.' unless result
|
72
|
+
end
|
73
|
+
|
74
|
+
BUILD_PRODUCTS_FOLDER = "./metamodel/Build/Products"
|
75
|
+
|
76
|
+
def copy_framework_swiftmodule_files
|
77
|
+
copy_command = "cp -rf #{BUILD_PRODUCTS_FOLDER}/Release-iphoneos/MetaModel.framework . && \
|
78
|
+
cp -rf #{BUILD_PRODUCTS_FOLDER}/Release-iphonesimulator/MetaModel.framework/Modules/MetaModel.swiftmodule/* \
|
79
|
+
MetaModel.framework/Modules/MetaModel.swiftmodule/"
|
80
|
+
system copy_command
|
81
|
+
end
|
82
|
+
|
83
|
+
def lipo_frameworks_on_different_archs
|
84
|
+
lipo_command = "lipo -create -output MetaModel.framework/MetaModel \
|
85
|
+
#{BUILD_PRODUCTS_FOLDER}/Release-iphonesimulator/MetaModel.framework/MetaModel \
|
86
|
+
#{BUILD_PRODUCTS_FOLDER}/Release-iphoneos/MetaModel.framework/MetaModel"
|
87
|
+
result = system "#{lipo_command}"
|
88
|
+
raise Informative, 'Copy framework to current folder failed.' unless result
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'xcodeproj'
|
2
|
+
|
3
|
+
module MetaModel
|
4
|
+
class Installer
|
5
|
+
class Renderer
|
6
|
+
include Config::Mixin
|
7
|
+
|
8
|
+
attr_reader :project
|
9
|
+
|
10
|
+
attr_reader :models
|
11
|
+
attr_reader :associations
|
12
|
+
|
13
|
+
def initialize(models, associations)
|
14
|
+
@models = models
|
15
|
+
@associations = associations
|
16
|
+
@project = Xcodeproj::Project.open(Config.instance.metamodel_xcode_project)
|
17
|
+
end
|
18
|
+
|
19
|
+
SWIFT_TEMPLATES_FILES = %w(
|
20
|
+
file_header
|
21
|
+
table_initialize
|
22
|
+
model_initialize
|
23
|
+
model_update
|
24
|
+
model_query
|
25
|
+
model_delete
|
26
|
+
static_methods
|
27
|
+
helper
|
28
|
+
)
|
29
|
+
|
30
|
+
def model_swift_templates
|
31
|
+
[].tap do |templates|
|
32
|
+
SWIFT_TEMPLATES_FILES.each do |file_path|
|
33
|
+
template = File.read File.expand_path(File.join(File.dirname(__FILE__), "../template/#{file_path}.swift"))
|
34
|
+
templates << template
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def render!
|
40
|
+
remove_previous_files_refereneces
|
41
|
+
UI.section "Generating model files" do
|
42
|
+
render_model_files
|
43
|
+
end
|
44
|
+
UI.section "Generating association files" do
|
45
|
+
render_association_files
|
46
|
+
end
|
47
|
+
@project.save
|
48
|
+
end
|
49
|
+
|
50
|
+
def remove_previous_files_refereneces
|
51
|
+
target = @project.targets.first
|
52
|
+
|
53
|
+
@models.each do |model|
|
54
|
+
target.source_build_phase.files_references.each do |file_ref|
|
55
|
+
target.source_build_phase.remove_file_reference(file_ref) if file_ref && "#{model.name}.swift" == file_ref.name
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
@associations.each do |association|
|
60
|
+
target.source_build_phase.files_references.each do |file_ref|
|
61
|
+
target.source_build_phase.remove_file_reference(file_ref) if file_ref && "#{association.class_name}.swift" == file_ref.name
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def render_model_files
|
67
|
+
target = @project.targets.first
|
68
|
+
|
69
|
+
models_group = @project.main_group.find_subpath('MetaModel/Models', true)
|
70
|
+
models_group.clear
|
71
|
+
models_group.set_source_tree('SOURCE_ROOT')
|
72
|
+
|
73
|
+
file_refs = []
|
74
|
+
@models.each do |model|
|
75
|
+
result = model_swift_templates.map { |template|
|
76
|
+
ErbalTemplate::render_from_hash(template, { :model => model })
|
77
|
+
}.join("\n")
|
78
|
+
model_path = Pathname.new("./metamodel/MetaModel/#{model.name}.swift")
|
79
|
+
File.write model_path, result
|
80
|
+
|
81
|
+
file_refs << models_group.new_reference(Pathname.new("MetaModel/#{model.name}.swift"))
|
82
|
+
|
83
|
+
UI.message '-> '.green + "Using #{model.name}.swift file"
|
84
|
+
end
|
85
|
+
target.add_file_references file_refs
|
86
|
+
end
|
87
|
+
|
88
|
+
def render_association_files
|
89
|
+
target = @project.targets.first
|
90
|
+
|
91
|
+
association_group = @project.main_group.find_subpath('MetaModel/Associations', true)
|
92
|
+
association_group.clear
|
93
|
+
association_group.set_source_tree('SOURCE_ROOT')
|
94
|
+
|
95
|
+
has_many_association_template = File.read File.expand_path(File.join(File.dirname(__FILE__), "../template/has_many_association.swift"))
|
96
|
+
belongs_to_association_template = File.read File.expand_path(File.join(File.dirname(__FILE__), "../template/belongs_to_association.swift"))
|
97
|
+
|
98
|
+
file_refs = []
|
99
|
+
@associations.each do |association|
|
100
|
+
template = association.relation == :has_many ? has_many_association_template : belongs_to_association_template
|
101
|
+
result = ErbalTemplate::render_from_hash(template, { :association => association })
|
102
|
+
file_name = "#{association.class_name}.swift"
|
103
|
+
File.write Pathname.new("./metamodel/MetaModel/#{file_name}"), result
|
104
|
+
|
105
|
+
file_refs << association_group.new_reference(Pathname.new("MetaModel/#{file_name}"))
|
106
|
+
|
107
|
+
UI.message '-> '.green + "Using #{file_name} file"
|
108
|
+
end
|
109
|
+
target.add_file_references file_refs
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module MetaModel
|
2
|
+
class Installer
|
3
|
+
class Validator
|
4
|
+
require 'metamodel/record/model'
|
5
|
+
require 'metamodel/record/property'
|
6
|
+
require 'metamodel/record/association'
|
7
|
+
|
8
|
+
def translate!
|
9
|
+
satisfy_constraint = @associations.reduce([]) do |remain, association|
|
10
|
+
expect = remain.select { |assoc| assoc.expect_constraint? association }
|
11
|
+
if expect.empty?
|
12
|
+
remain << association
|
13
|
+
else
|
14
|
+
remain.delete expect.first
|
15
|
+
end
|
16
|
+
remain
|
17
|
+
end
|
18
|
+
raise Informative, "Unsatisfied constraints in #{satisfy_constraint.map \
|
19
|
+
{ |x| x.debug_description }}" if satisfy_constraint.size > 0
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def validate_models
|
24
|
+
existing_types = @models.map { |m| m.properties.map { |property| property.type } }.flatten.uniq
|
25
|
+
unsupported_types = existing_types - supported_types
|
26
|
+
raise Informative, "Unsupported types #{unsupported_types}" unless unsupported_types == []
|
27
|
+
end
|
28
|
+
|
29
|
+
CURRENT_SUPPORTED_BUILT_IN_TYPES = %w[
|
30
|
+
Int
|
31
|
+
Double
|
32
|
+
Float
|
33
|
+
String
|
34
|
+
Bool
|
35
|
+
NSDate
|
36
|
+
]
|
37
|
+
|
38
|
+
def built_in_types
|
39
|
+
CURRENT_SUPPORTED_BUILT_IN_TYPES.map do |t|
|
40
|
+
[t, "#{t}?"]
|
41
|
+
end.flatten
|
42
|
+
end
|
43
|
+
|
44
|
+
def supported_types
|
45
|
+
@models.reduce(CURRENT_SUPPORTED_BUILT_IN_TYPES) { |types, model|
|
46
|
+
types << model.name.to_s
|
47
|
+
}.map { |type|
|
48
|
+
[type, "#{type}?"]
|
49
|
+
}.flatten
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "metamodel/metafile/dsl"
|
2
|
+
|
3
|
+
module MetaModel
|
4
|
+
class Metafile
|
5
|
+
include MetaModel::Metafile::DSL
|
6
|
+
|
7
|
+
attr_accessor :defined_in_file
|
8
|
+
attr_accessor :current_model
|
9
|
+
|
10
|
+
attr_accessor :models
|
11
|
+
attr_accessor :associations
|
12
|
+
|
13
|
+
def initialize(defined_in_file = nil, internal_hash = {})
|
14
|
+
@defined_in_file = defined_in_file
|
15
|
+
@models = []
|
16
|
+
@associations = []
|
17
|
+
|
18
|
+
evaluate_model_definition(defined_in_file)
|
19
|
+
amend_association
|
20
|
+
end
|
21
|
+
|
22
|
+
def evaluate_model_definition(path)
|
23
|
+
UI.section "Analyzing Metafile" do
|
24
|
+
contents ||= File.open(path, 'r:utf-8', &:read)
|
25
|
+
|
26
|
+
if contents.respond_to?(:encoding) && contents.encoding.name != 'UTF-8'
|
27
|
+
contents.encode!('UTF-8')
|
28
|
+
end
|
29
|
+
|
30
|
+
eval(contents, nil, path.to_s)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.from_file(path)
|
35
|
+
path = Pathname.new(path)
|
36
|
+
unless path.exist?
|
37
|
+
raise Informative, "No Metafile exists at path `#{path}`."
|
38
|
+
end
|
39
|
+
|
40
|
+
case path.extname
|
41
|
+
when '', '.metafile'
|
42
|
+
Metafile.new(path)
|
43
|
+
else
|
44
|
+
raise Informative, "Unsupported Metafile format `#{path}`."
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def amend_association
|
49
|
+
name_model_hash = Hash[@models.collect { |model| [model.name, model] }]
|
50
|
+
@associations.map! do |association|
|
51
|
+
major_model = name_model_hash[association.major_model]
|
52
|
+
major_model.associations << association
|
53
|
+
association.major_model = major_model
|
54
|
+
association.secondary_model = name_model_hash[association.secondary_model]
|
55
|
+
raise Informative, "Associations not satisfied in `Metafile`" unless [association.major_model, association.secondary_model].compact.size == 2
|
56
|
+
association
|
57
|
+
end
|
58
|
+
self
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module MetaModel
|
2
|
+
class Metafile
|
3
|
+
module DSL
|
4
|
+
require 'metamodel/record/model'
|
5
|
+
require 'metamodel/record/property'
|
6
|
+
require 'metamodel/record/association'
|
7
|
+
|
8
|
+
def metamodel_version(version)
|
9
|
+
raise Informative,
|
10
|
+
"Meta file #{version} not matched with current metamodel version #{VERSION}" if version != VERSION
|
11
|
+
end
|
12
|
+
|
13
|
+
def define(model_name)
|
14
|
+
UI.message '-> '.green + "Resolving `#{model_name.to_s.camelize}`"
|
15
|
+
@current_model = Record::Model.new(model_name)
|
16
|
+
yield if block_given?
|
17
|
+
@models << @current_model
|
18
|
+
end
|
19
|
+
|
20
|
+
def attr(key, type = :string, **args)
|
21
|
+
@current_model.properties << Record::Property.new(key, type, args)
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_one(name, model_name = nil, **args)
|
25
|
+
model_name = name.to_s.singularize.camelize if model_name.nil?
|
26
|
+
association = Record::Association.new(name, current_model.name, model_name, :has_one, args)
|
27
|
+
@associations << association
|
28
|
+
end
|
29
|
+
|
30
|
+
def has_many(name, model_name = nil, **args)
|
31
|
+
model_name = name.to_s.singularize.camelize if model_name.nil?
|
32
|
+
raise Informative, "has_many relation can't be created with optional model name" if model_name.end_with? "?"
|
33
|
+
association = Record::Association.new(name, current_model.name, model_name, :has_many, args)
|
34
|
+
@associations << association
|
35
|
+
end
|
36
|
+
|
37
|
+
def belongs_to(name, model_name = nil, **args)
|
38
|
+
model_name = name.to_s.singularize.camelize if model_name.nil?
|
39
|
+
association = Record::Association.new(name, current_model.name, model_name, :belongs_to, args)
|
40
|
+
@associations << association
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|