Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Generate Swift constants for Xcode storyboards containing cell reuse identifiers, segue identifiers and storyboard identifier. More information: https://www.ralfebert.de/storyboard-constants/
#!/usr/bin/env ruby
require 'nokogiri'
def show_usage(msg = nil)
puts "#{msg}\n\n" if msg
puts "Usage:\n\t#{$PROGRAM_NAME} [storyboard_file]"
exit(0)
end
def swift_name(name)
name = name.gsub(/[^0-9A-Z_]/i, '')
name[0].downcase + name[1..-1]
end
def constant(name, value)
"var #{name}: String { return \"#{value}\" }"
end
def extension_for_class(cl)
ids = (cl.xpath(".//*[@reuseIdentifier]/@reuseIdentifier") + cl.xpath(".//*[@identifier]/@identifier"))
declarations = ids.map { |e| constant(swift_name(e.to_s), e) }
declarations.push "static " + constant("storyboardIdentifier", cl['storyboardIdentifier']) if cl['storyboardIdentifier']
return if declarations.empty?
<<-END
extension #{cl['customClass']} {
#{declarations.map {|line| "\t" + line }.join("\n")}
}
END
end
show_usage unless ARGV.count == 1
fname_storyboard = ARGV[0]
show_usage "Storyboard file not found: #{fname_storyboard}" unless File.exist?(fname_storyboard)
doc = File.open(fname_storyboard) { |f| Nokogiri::XML(f) }
show_usage "#{fname_storyboard} doesn't seem to be a storyboard" unless doc.root.name == "document"
extensions = doc.xpath(".//*[@customClass]").map { |cl| extension_for_class(cl) }
puts "// Generated with https://www.ralfebert.de/storyboard-constants/\n\n" + extensions.join.strip
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.