Skip to content

Instantly share code, notes, and snippets.

@Goos
Last active August 29, 2015 14:22
Show Gist options
  • Save Goos/92b7cbc7328ff538a550 to your computer and use it in GitHub Desktop.
Save Goos/92b7cbc7328ff538a550 to your computer and use it in GitHub Desktop.
A hacky script that takes .xcassets directories and produces a Swift file defining an enum with a case for each image in the asset directories, as well as an UIImage convenience initializer that takes said enum as an argument instead of a string. This enables compiler-checked UIImage initialization returning non-optional images. Inspired by the …
require "pathname"
class XCAsset
def initialize(path, is_root)
@path = path
@is_root = is_root
name = @path.split.last
@is_container = !(name.to_s =~ /\.imageset$/)
if @is_container
@name = name.to_s.sub(".xcassets", "")
@children = @path.children.select { |child|
!(child.to_s =~ /\.appiconset$/) and child.directory?
}.map { |child|
XCAsset.new(child, false)
}.sort_by { |asset| asset.container? ? 0 : 1 }
else
@name = name.to_s.sub(".imageset", "")
end
end
def name
@name
end
def children
@children
end
def container?
@is_container
end
def root?
@is_root
end
end
class StringRenderer
def render(assets)
@tablevel = 0
str = "import UIKit\n\n"
str += "extension UIImage {"
@tablevel += 1
str += "\n#{tabstring}enum AssetIdentifier: String {\n"
assets.each { |child|
if child.container?
str += render_container(child)
else
str += render_identifier(child)
end
str += "\n"
}
str += "#{tabstring}}"
str += render_initializers()
str += "\n}"
end
def tabstring
(0...@tablevel).reduce("") { |x,y| x += " " }
end
def render_container(container)
@tablevel += 1
str = "#{tabstring}"
if container.root?
str += "/* #{container.name} */"
else
str += "// #{container.name}"
end
container.children.each { |child|
str += "\n"
if child.container?
str += render_container(child) if child.children.count > 0
else
str += render_identifier(child)
end
}
@tablevel -= 1
str += "\n"
str
end
def render_identifier(asset)
name_without_spaces = asset.name.sub(" ", "")
"#{tabstring}case #{name_without_spaces} = \"#{asset.name}\""
end
def render_initializers
str = "\n\n#{tabstring}convenience init!(assetIdentifier: AssetIdentifier) {"
@tablevel += 1
str += "\n#{tabstring}self.init(named: assetIdentifier.rawValue)"
@tablevel -= 1
str += "\n#{tabstring}}"
str
end
end
renderer = StringRenderer.new()
srcroot = nil
input_files = []
output_file = nil
ENV.each do |arg|
key = arg.first
val = arg.last
if key =~ /^SCRIPT_INPUT_FILE(?!_COUNT)/ && val =~ /.xcassets$/
input_files.push val
elsif key =~ /^SCRIPT_OUTPUT_FILE/
output_file = val
elsif key =~ /^SRCROOT/
srcroot = val
end
end
if input_files.empty?
puts "Error: None or improper input files specified."
exit
end
if output_file == nil
puts "Error: No output file specified."
exit
end
asset_folders = input_files.map { |path|
p = Pathname.new(path)
XCAsset.new(p, true)
}
content = renderer.render(asset_folders)
File.open(output_file, 'w+') { |f| f.write(content) }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment