Last active
August 29, 2015 14:19
-
-
Save chuganzy/1f74224d7c62f01654ec to your computer and use it in GitHub Desktop.
xcdatamodeldからSwiftのコードをいい感じに吐く
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'nokogiri' | |
require 'colorize' | |
require 'erubis' | |
class Manager | |
class SwiftConverter | |
def to_swift | |
raise 'Error: method `to_swift` is not implemented' | |
end | |
end | |
class SwiftType < SwiftConverter | |
def self.is_optional(xml) | |
xml['optional'] == 'YES' | |
end | |
def initialize(model_type, is_optional, should_convert = true) | |
@is_optional = is_optional | |
if !should_convert | |
@type = model_type | |
return | |
end | |
case model_type | |
when /^Integer (\d+)/ | |
type = "Int#{$1}" | |
when 'Decimal' | |
type = 'NSDecimal' | |
when 'Boolean' | |
type = 'Bool' | |
when 'Date' | |
type = 'NSTimeInterval' | |
when 'Binary' | |
type = 'NSData' | |
when 'Transformable' | |
type = 'AnyObject' | |
else | |
type = model_type | |
end | |
@type = type | |
end | |
def to_swift | |
if !@is_optional | |
return @type | |
end | |
@type + '?' | |
end | |
end | |
class SwiftXmlConverter < SwiftConverter | |
attr_reader :xml | |
def initialize(xml) | |
@xml = xml | |
end | |
end | |
class Entity < SwiftXmlConverter | |
attr_reader :class_name, :parent_class_name | |
def initialize(xml) | |
super(xml) | |
@attributes = [] | |
@class_name = xml['representedClassName'] | |
xml.xpath('attribute').each do |xml| | |
attribute = Attribute.new(xml) | |
@attributes.push(attribute) | |
end | |
end | |
def setup_relationships(entities) | |
entities_type_dictionary = {} | |
entities.each do |entity| | |
entities_type_dictionary[entity.xml['name']] = entity.class_name | |
end | |
if @xml['parentEntity'] | |
@parent_class_name = entities_type_dictionary[@xml['parentEntity']] | |
else | |
@parent_class_name = 'NSManagedObject' | |
end | |
@relationships = [] | |
@xml.xpath('relationship').each do |xml| | |
relationship = Relationship.new(xml, entities_type_dictionary) | |
@relationships.push(relationship) | |
end | |
end | |
def to_swift | |
attribute_swift = '' | |
template = <<"SWIFT" | |
// | |
// THIS IS GENERATED CODE. | |
// DO NOT MAKE ANY CHANGES. | |
// | |
import CoreData | |
@objc(<%= @entity.class_name %>) | |
class <%= @entity.class_name %>: <%= @entity.parent_class_name %> { | |
<% @attributes.each do |attribute| %> | |
<%= attribute.to_swift %> | |
<% end %> | |
<% @relationships.each do |relationship| %> | |
<%= relationship.to_swift %> | |
<% if relationship.type.start_with?('NSOrderedSet') %> | |
func <%= relationship.name %>Set() -> NSMutableOrderedSet { | |
self.willAccessValueForKey("<%= relationship.name %>") | |
let result = self.mutableOrderedSetValueForKey("<%= relationship.name %>") | |
self.didAccessValueForKey("<%= relationship.name %>") | |
return result | |
} | |
<% end %> | |
<% end %> | |
} | |
SWIFT | |
erb = Erubis::Eruby.new(template) | |
data = { | |
'entity' => self, | |
'attributes' => @attributes, | |
'relationships' => @relationships | |
} | |
erb.evaluate(data) | |
end | |
end | |
class Attribute < SwiftXmlConverter | |
def initialize(xml) | |
super(xml) | |
end | |
def to_swift | |
type = SwiftType.new(@xml['attributeType'], SwiftType.is_optional(@xml)) | |
"@NSManaged var #{@xml['name']}: #{type.to_swift}" | |
end | |
end | |
class Relationship < SwiftXmlConverter | |
attr_reader :name, :type | |
def initialize(xml, entities_type_dictionary) | |
super(xml) | |
@entities_type_dictionary = entities_type_dictionary | |
if @xml['toMany'] == 'YES' | |
if @xml['ordered'] == 'YES' | |
type = 'NSOrderedSet' | |
else | |
type = 'NSSet' | |
end | |
else | |
type = @entities_type_dictionary[@xml['destinationEntity']] | |
end | |
type = SwiftType.new(type, SwiftType.is_optional(@xml), false) | |
@name = @xml['name'] | |
@type = type.to_swift | |
end | |
def to_swift | |
"@NSManaged var #{@name}: #{@type}" | |
end | |
end | |
def initialize(model_base_path, model_name) | |
@model_base_path = model_base_path | |
path = @model_base_path + "/#{model_name}.xcdatamodeld/#{model_name}.xcdatamodel/contents" | |
f = File.open(path, 'r') do |file| | |
@xml = Nokogiri::XML(file) | |
end | |
end | |
def update_model | |
entities = [] | |
@xml.xpath('/model/entity').each do |entity| | |
entity = Entity.new(entity) | |
entities.push(entity) | |
end | |
entities.each do |entity| | |
entity.setup_relationships(entities) | |
file_name = "#{entity.class_name}.swift" | |
puts "Updating: #{file_name}".bold | |
File.open("#{@model_base_path}/#{file_name}", 'w') do |file| | |
file.puts(entity.to_swift) | |
end | |
end | |
end | |
end | |
if __FILE__ == $PROGRAM_NAME | |
base_path = File.expand_path("#{__dir__}/../Sumally/Model") # absolute path to your .xcdatamodeld base path | |
name = 'Model' # name of your .xcdatamodeld | |
manager = Manager.new(base_path, name) | |
manager.update_model() | |
puts "Update Complete!".green | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment