Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The Model Generation Script Fix #27

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 99 additions & 35 deletions Source/ModelScript/modelgen-swift.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
MAPPING_KEY_DEFAULT = "default"
MAPPING_KEY_KEY = "key"
MAPPING_KEY_NONOPTIONAL = "nonoptional"
MAPPING_KEY_TRANSFORMER = "transformer"
MAPPING_KEY_TRANSFORMER = "transformer"
MAPPING_KEY_COLLECTION_SUBTYPE = "collection_subtype"

STRING_IMPORT_FOUNDATION = "import Foundation\n"
STRING_IMPORT_FOUNDATION = "import Foundation\nimport US2MapperKit\n"
STRING_IMPORT_FOUNDATION_TEST = "import Foundation\n"

STRING_REQUIRED_INIT_START = "\n\trequired init("
STRING_MAP_VALUES_DICT_START = "\n\n\tprivate func setValues("
STRING_MAP_DICT_START = '\n\n\tfunc updateWithDictionary(dictionary: Dictionary<String, AnyObject>) {\n\n\t\tlet dynamicTypeString = "\(self.dynamicType)"\n\t\tlet className = dynamicTypeString.componentsSeparatedByString(".").last\n\n\t\tif let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) {'
Expand All @@ -42,8 +44,8 @@
STRING_USMAPPER_IMPORT = "\n"
STRING_USMAPPER_INHERITENCE = "\nclass US2Instantiator : US2InstantiatorProtocol {\n\n"

def generate_model(mappinglist, output_directory, version):
def generate_model(mappinglist, output_directory, version, testEnabled):

for mapping in mappinglist:
filename = mapping[mapping.rindex('/',0,-1)+1:-1] if mapping.endswith('/') else mapping[mapping.rindex('/')+1:]
classname = filename.split('.', 1 )[0]
Expand All @@ -52,16 +54,17 @@ def generate_model(mappinglist, output_directory, version):

validate_class_mapping_configuration(classname, mappingPlist)

generate_internal_file(mappingPlist, classname, output_directory)
generate_external_file_if_needed(classname, output_directory)
generate_internal_file(mappingPlist, classname, output_directory, testEnabled)
generate_external_file_if_needed(classname, output_directory, testEnabled)

generate_internal_instantiator_file(mappinglist, output_directory)
generate_internal_instantiator_file(mappinglist, output_directory, testEnabled)


'''
External Model File Generation

'''
def generate_external_file_if_needed(classname, class_directory):
def generate_external_file_if_needed(classname, class_directory, testEnabled):

filename = class_directory + classname + '.swift'

Expand All @@ -72,15 +75,21 @@ def generate_external_file_if_needed(classname, class_directory):
os.makedirs(os.path.dirname(filename))

outputfile = open(filename, "wba")

outputfile.write(STRING_IMPORT_FOUNDATION + '\nclass ' + classname + ' : _' + classname + ' {\n\n}')

if testEnabled == 1:
print 'TEST ENABLED'
outputfile.write(STRING_IMPORT_FOUNDATION_TEST + '\nclass ' + classname + ' : _' + classname + ' {\n\n}')
else:
print 'TEST DISABLED'
outputfile.write(STRING_IMPORT_FOUNDATION + '\nclass ' + classname + ' : _' + classname + ' {\n\n}')

outputfile.close();


'''
Internal Model File Generation
'''
def generate_internal_file(mappingPlist, classname, class_directory):
def generate_internal_file(mappingPlist, classname, class_directory, testEnabled):

filename = class_directory + 'Internal/_'+ classname + '.swift'

Expand All @@ -89,7 +98,13 @@ def generate_internal_file(mappingPlist, classname, class_directory):

outputfile = open(filename, "wba")

outputfile.write(STRING_IMPORT_FOUNDATION + STRING_USMAPPER_IMPORT + '\nclass _' + classname + ' {\n')
if testEnabled is '1':
print 'TEST ENABLED'
outputfile.write(STRING_IMPORT_FOUNDATION_TEST + STRING_USMAPPER_IMPORT + '\nclass _' + classname + ' {\n')
else:
print 'TEST DISABLED'
outputfile.write(STRING_IMPORT_FOUNDATION + STRING_USMAPPER_IMPORT + '\nclass _' + classname + ' {\n')


append_optional_property_definitions(outputfile, mappingPlist)
append_non_optional_property_definitions(outputfile, mappingPlist)
Expand All @@ -103,6 +118,7 @@ def generate_internal_file(mappingPlist, classname, class_directory):

'''
Appeand Properties

'''
def append_optional_property_definitions(classfile, mappingPlist):
classfile.write('\n')
Expand Down Expand Up @@ -152,15 +168,18 @@ def append_non_optional_property_definitions(classfile, mappingPlist):
def append_instance_property(classfile, propertyname, datatype, optional):
classfile.write(STRING_PROPERTY_VAR + ' ' + propertyname + ' : ' + datatype + '{}\n'.format('?' if optional else ''))


def append_array_instance_property(classfile, propertyname, collectionSubtype, optional):
classfile.write(STRING_PROPERTY_VAR + ' ' + propertyname + ' : [' + collectionSubtype + ']{}\n'.format('?' if optional else ''))


def append_dictionary_instance_property(classfile, propertyname, collectionSubtype, optional):
classfile.write(STRING_PROPERTY_VAR + ' ' + propertyname + ' : Dictionary<String,' + collectionSubtype + '>{}\n'.format('?' if optional else ''))


'''
Append Required Initializer

'''
def append_required_initializer(classFile, mappingPlist):
classFile.write(STRING_REQUIRED_INIT_START)
Expand Down Expand Up @@ -199,6 +218,7 @@ def append_required_initializer_non_optional_property(classFile, mappingPlist, p

'''
Append Failable Initializer

'''
def append_failable_initializer(classFile, mappingPlist):

Expand Down Expand Up @@ -226,7 +246,6 @@ def append_failable_initializer(classFile, mappingPlist):
else:
append_swift_1_2_failable_reinitialization(classFile, mappingPlist)


def append_swift_1_2_failable_reinitialization(classFile, mappingPlist):

classFile.write(' \n } else {\n self.init(')
Expand Down Expand Up @@ -301,39 +320,55 @@ def append_failable_initializer_typecasting(classFile, mappingPlist):
def append_failable_typecast_unwrap_statement(classFile, propertyName):
classFile.write('\n\t\t\tif let unwrapped_' + propertyName + ' : Any = valuesDict["' + propertyName + '"] {\n\t\t\t\t' + propertyName + ' = typeCast(unwrapped_' + propertyName + ')\n\t\t\t}\n')


def append_failed_initialiser_property(classfile, propertyname, datatype, optional, isFirstLine):
if datatype not in NATIVE_PROPERTY_TYPES:
classfile.write('{}_'.format('' if isFirstLine else ',\n\t\t\t\t ') + propertyname + ' : ' + datatype + '(Dictionary<String, AnyObject>())!{}'.format('?' if optional else ''))
else:
classfile.write('{}_'.format('' if isFirstLine else ',\n\t\t\t\t ') + propertyname + ' : ' + datatype + '(){}'.format('?' if optional else ''))


def append_array_failed_initialiser_property(classfile, propertyname, datatype, collectionSubtype, optional, isFirstLine):
classfile.write('{}_'.format('' if isFirstLine else ',\n\t\t\t\t ') + propertyname + ' : [' + collectionSubtype + '](){}'.format('?' if optional else ''))


def append_dictionary_failed_initialiser_property(classfile, propertyname, datatype, collectionSubtype, optional, isFirstLine):
classfile.write( '{}_'.format('' if isFirstLine else ',\n\t\t\t\t ') + propertyname + ' : Dictionary<String,' + collectionSubtype + '>(){}'.format('?' if optional else ''))


'''
Create External US2Mapper Inherited File

'''
def generate_internal_instantiator_file(mappingPlist, output_directory):
def generate_internal_instantiator_file(mappingPlist, output_directory, testEnabled):
filename = output_directory + 'Internal/US2Instantiator.swift'

if not os.path.exists(os.path.dirname(filename)):
os.makedirs(os.path.dirname(filename))

outputfile = open(filename, "wba")

outputfile.write(STRING_FILE_INTRO + STRING_IMPORT_FOUNDATION + STRING_USMAPPER_IMPORT)

if testEnabled == 1:
outputfile.write(STRING_FILE_INTRO + STRING_IMPORT_FOUNDATION_TEST + STRING_USMAPPER_IMPORT)
else:
outputfile.write(STRING_FILE_INTRO + STRING_IMPORT_FOUNDATION + STRING_USMAPPER_IMPORT)

classnames = []

for mapping in mappingPlist:
filename = mapping[mapping.rindex('/',0,-1)+1:-1] if mapping.endswith('/') else mapping[mapping.rindex('/')+1:]
classname = filename.split('.', 1 )[0]
classnames.append(classname)

append_mapper_class_enum(classnames, outputfile)
append_mapper_method_definitions(outputfile, mappingPlist)
append_mapping_dict_enum(classnames, outputfile)
append_instantiator_protocol(outputfile)

outputfile.close();


def append_mapper_class_enum(classnames, outputfile):
outputfile.write('enum US2MapperClassEnum: String {')

for classname in classnames:
Expand All @@ -346,15 +381,34 @@ def generate_internal_instantiator_file(mappingPlist, output_directory):
outputfile.write('\n\t\tcase ._' + classname + ':\n\t\t\treturn '+ classname + '(data)' )

outputfile.write('\n\t\tcase ._None:\n\t\t\treturn nil' )

outputfile.write('\n\t\t}\n\t}\n}\n\n')

append_mapper_method_definitions(outputfile, mappingPlist)

outputfile.write('\n\nclass US2Instantiator : US2InstantiatorProtocol {\n\n\tstatic let sharedInstance : US2Instantiator = US2Instantiator()\n\n\tfunc newInstance(ofType classname : String, withValue data : Dictionary<String, AnyObject>) -> AnyObject? {\n\t\treturn US2MapperClassEnum(rawValue: classname)?.createObject(data)\n\t}\n\n' )
def append_mapping_dict_enum(classnames, outputfile):
outputfile.write('\n\nenum US2MappingEnum : String {')


outputfile.write('\tfunc transformerFromString(classString: String) -> US2TransformerProtocol? {\n\t\treturn US2TransformerEnum(rawValue: classString)!.transformer()\n\t}\n}')
outputfile.close();
for classname in classnames:
outputfile.write('\n\tcase _' + classname + ' \t= "'+ classname + '"' )

outputfile.write('\n\tcase _None\t\t\t\t= "None"')
outputfile.write('\n\n\tfunc mapping() -> Dictionary<String, Dictionary<String, AnyObject>>? {\n\t\tvar mappingDict = Dictionary<String, Dictionary<String, AnyObject>> ()\n\n\t\tswitch self {')
#outputfile.write('\t\t\t\tvar mappingDict = Dictionary<String, Dictionary<String, AnyObject>> ()' )


for classname in classnames:
#outputfile.write('\n\t\tcase ._' + classname + ':\n\t\t\treturn '+ classname + '(data)' )
outputfile.write('\n\t\t\tcase ._' + classname + ':\n')
outputfile.write('\n\t\t\treturn mappingDict' )

#var mappingDict = Dictionary<String, Dictionary<String, AnyObject>> ()
# mappingDict["optionalSubType"] = ["key" : "optional_subtype", "type" : "TestObjectThree"]
# mappingDict["non_optionalSubType"] = ["key" : "non_optional_subtype", "type" : "TestObjectThree", "nonoptional" : true]
# return mappingDict
#outputfile.write('\n\t\tcase ._' + classname + ':\n\t\t\treturn nil' )

outputfile.write('\n\t\tcase ._None:\n\t\t\treturn nil' )
outputfile.write('\n\t\t}\n\t}\n}\n\n')


def append_mapper_method_definitions(classfile, mappinglist):
Expand All @@ -378,12 +432,17 @@ def append_mapper_method_definitions(classfile, mappinglist):
classfile.write('\n\n\tfunc transformer() -> US2TransformerProtocol? {\n\t\tswitch self {')

for mapperClass in distinctMapperClassDefinitions:
classfile.write('\n\t\tcase ._' + mapperClass + ':\n\t\t\treturn ' + mapperClass + '()\n' )
classfile.write('\n\t\tcase ._' + mapperClass + ':\n\t\t\treturn ' + mapperClass + '()' )

classfile.write('\n\t\tcase ._None:\n\t\t\treturn nil' )
classfile.write('\n\t\t}\n\t} \n}')

classfile.write('\t\t}\n\t} \n}')

def append_instantiator_protocol(outputfile):
outputfile.write('\n\nclass US2Instantiator : US2InstantiatorProtocol {\n\n\tstatic let sharedInstance : US2Instantiator = US2Instantiator()\n\n\tfunc newInstance(ofType classname : String, withValue data : Dictionary<String, AnyObject>) -> AnyObject? {\n\t\treturn US2MapperClassEnum(rawValue: classname)?.createObject(data)\n\t}\n\n' )
outputfile.write('\tfunc transformerFromString(classString: String) -> US2TransformerProtocol? {\n\t\treturn US2TransformerEnum(rawValue: classString)!.transformer()\n\t}\n\n')
outputfile.write('\tfunc mappingForClass(classString: String) -> Dictionary<String, Dictionary<String, AnyObject>>? {\n\t\treturn US2MappingEnum(rawValue: classString)!.mapping()\n\t}\n\n}')


'''
Create Mapping for Instantiated Class
Expand Down Expand Up @@ -454,35 +513,40 @@ def throw_missing_json_key_error(classname, propertykey, mapping):
print "The mapping configuration for the " + propertykey + " property is missing the key configuration.\nAll properties must specify a 'key' value to map against value in a dictionary.\n\n"
raise Exception('Invalid Configuration')


def xcode_version():
status, xcodeVersionString = commands.getstatusoutput("xcodebuild -version")
if xcodeVersionString.find("Xcode 7.") != -1:
return 7.0
else:
return 6.0


def main(argv):
inputfile = ''
outputfile = ''
testEnabled = 0

try:
opts, args = getopt.getopt(argv,"hv:i:o:",["version=", "mapdir=", "classdir="])
opts, args = getopt.getopt(argv,"hv:i:o:t:",["version=","mapdir=","classname=","testing="])
except getopt.GetoptError:
print 'test.py -v <version> -i <mapdir> -o <classdir>'
print 'test.py -i <inputfile> -o <outputfile>'
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print 'test.py -v <version> -i <mapdir> -o <classdir>'
print 'test.py -i <inputfile> -o <outputfile>'
sys.exit()
elif opt in ("-v", "--version"):
version = arg
elif opt in ("-i", "--mapdir"):
elif opt in ("-v", "--ifile"):
currentVersion = arg
elif opt in ("-i", "--ofile"):
mapdir = arg
elif opt in ("-o", "--classdir"):
elif opt in ("-o", "--ifile"):
classdir = arg

elif opt in ("-t", "--ofile"):
testEnabled = arg
mappinglist = glob.glob(mapdir + "*.plist")
generate_model(mappinglist, classdir, version)

generate_model(mappinglist, classdir, currentVersion, testEnabled)

print 'Input file is "', inputfile
print 'Output file is "', outputfile

if __name__ == "__main__":
main(sys.argv[1:])
33 changes: 26 additions & 7 deletions Source/US2MapperKit/US2Mapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Foundation
public protocol US2InstantiatorProtocol {
func newInstance(ofType classname : String, withValue data : Dictionary<String, AnyObject>) -> AnyObject?
func transformerFromString(classString: String) -> US2TransformerProtocol?
func mappingForClass(classString: String) -> Dictionary<String, Dictionary<String, AnyObject>>?
}

public protocol US2TransformerProtocol {
Expand Down Expand Up @@ -54,7 +55,7 @@ final public class US2Mapper {

public class func mapValues(from dictionary : Dictionary<String, AnyObject>, forType classType : String , employing instantiator : US2InstantiatorProtocol, defaultsEnabled : Bool) -> Dictionary<String, Any>? {

if let mappingConfiguration = retrieveMappingConfiguration(classType) {
if let mappingConfiguration = retrieveMappingConfiguration(classType, employing: instantiator) {

// Dictionary to store parsed values to be returned
var retrievedValueDictionary = Dictionary<String, Any>()
Expand All @@ -75,20 +76,38 @@ final public class US2Mapper {
return nil
}

class func retrieveMappingConfiguration(className : String) -> Dictionary<String, Dictionary<String, AnyObject>>? {
class func retrieveMappingConfiguration(className : String, employing instantiator : US2InstantiatorProtocol) -> Dictionary<String, Dictionary<String, AnyObject>>? {

if let mappingconfiguration = propertyMappings[className] {
return mappingconfiguration
} else {
if let mappingPath = NSBundle(forClass: self).pathForResource(className, ofType: "plist") {
let tempMapping = NSDictionary(contentsOfFile: mappingPath) as? Dictionary<String, Dictionary<String, AnyObject>>

if tempMapping!.isEmpty { return nil }

NSProcessInfo.processInfo().arguments.containsValue("TEST")
if NSProcessInfo.processInfo().arguments.containsValue("TEST") {
if let mappingPath = NSBundle(forClass: self).pathForResource(className, ofType: "plist"),
let tempMapping = NSDictionary(contentsOfFile: mappingPath) as? Dictionary<String, Dictionary<String, AnyObject>> {
if tempMapping.keys.count > 0 {
propertyMappings[className] = tempMapping
return tempMapping
}

return nil

} else {
return nil
}
} else {
if let mappingPath = NSBundle.mainBundle().pathForResource(className, ofType: "plist"),

let tempMapping = NSDictionary(contentsOfFile: mappingPath) as? Dictionary<String, Dictionary<String, AnyObject>> {

propertyMappings[className] = tempMapping
return tempMapping!
return tempMapping
} else {
return nil
}

}
}
}
}
Expand Down
Loading