Last active
August 29, 2015 14:26
-
-
Save ebaker355/d282b22abc6a92aa6767 to your computer and use it in GitHub Desktop.
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 | |
# | |
# ExtractStoryboardIdentifiers.rb | |
# | |
# By Eric Baker. | |
# 25/August/2015 | |
# | |
# Call this script from a Run Script build phase: | |
# Shell: /bin/sh | |
# | |
# "${SRCROOT}/ExtractStoryboardIdentifiers.rb" "${SRCROOT}" "${SRCROOT}/App" AAA [--swift] | |
# | |
# The first arg is the project path, which will be searched for storyboard files | |
# The second arg is the output path | |
# The third arg is the class prefix | |
# | |
# The generated files will be AAAStoryboardIdentifiers.h/.m | |
# You should add these files to your Xcode project after they have been generated | |
# by this script for the first time. | |
# | |
require 'English' | |
# TODO: Better parsing of cmd line args | |
project_dir = ARGV[0] | |
output_path = ARGV[1] | |
class_prefix = ARGV[2] | |
format_as_swift = false | |
ARGV.each { |arg| | |
format_as_swift = true if arg.eql? "--swift" | |
} | |
class Storyboard | |
attr_reader :name | |
attr_reader :filename | |
attr_reader :path | |
attr_reader :segueIdentifiers | |
attr_reader :storyboardIdentifiers | |
def self.find_storyboard_files_in_path(path) | |
storyboards = [] | |
Dir.glob("#{path}/**/*.storyboard").each { |item| | |
name = File.basename(item).gsub '.storyboard', '' | |
path = File.dirname(item) | |
s = Storyboard.new(name, path) | |
storyboards << s | |
} | |
storyboards | |
end | |
def initialize(name, path) | |
@name = name | |
@name = "#{name}Storyboard" unless @name.end_with? "Storyboard" | |
@filename = name | |
@path = path | |
@segueIdentifiers = [] | |
@storyboardIdentifiers = [] | |
end | |
def name_with_language | |
if !self.language.empty? | |
"#{@name}_#{self.language}" | |
else | |
@name | |
end | |
end | |
def language | |
language = "" | |
# If the path contains a .lproj component, extract the language from it. | |
if @path.include? '.lproj' | |
@path.split('/').each { |item| | |
if item.include? '.lproj' | |
language = item.gsub '.lproj', '' | |
break | |
end | |
} | |
end | |
language = "" if language.eql? "Base" | |
language | |
end | |
def file_contents | |
if @file_contents.nil? | |
@file_contents = File.read(File.join(@path, "#{@filename}.storyboard")) | |
end | |
@file_contents | |
end | |
def segue_identifiers | |
self.file_contents.scan(/<segue.*identifier="(\w+)"/).flatten.uniq.sort | |
end | |
def storyboard_identifiers | |
self.file_contents.scan(/storyboardIdentifier="(\w+)"/).flatten.uniq.sort | |
end | |
def reuse_identifiers | |
self.file_contents.scan(/reuseIdentifier="(\w+)"/).flatten.uniq.sort | |
end | |
def to_s | |
"#{self.class.name} -> @name `#{@name}`;\n@path `#{@path}`;\nlanguage `#{self.language}`;\nsegue_identifiers `#{self.segue_identifiers}`;\nstoryboard_identifiers `#{self.storyboard_identifiers}`;\nreuse_identifiers `#{self.reuse_identifiers}`" | |
end | |
end | |
class SourceFileGenerator | |
def initialize(path, file_name, storyboards) | |
@path = path | |
@file_name = file_name | |
@storyboards = storyboards | |
end | |
def file_path | |
File.join(@path, @file_name) | |
end | |
def header_file_path | |
"#{self.file_path}.h" | |
end | |
def implementation_file_path | |
"#{self.file_path}.m" | |
end | |
def swift_file_path | |
"#{self.file_path}.swift" | |
end | |
def create_header_file | |
header = [] | |
header << "// This file was generated by a run script. Do not edit." | |
header << "" | |
header << "#import <Foundation/Foundation.h>" | |
@storyboards.sort! { |l,r| l.name_with_language <=> r.name_with_language } | |
@storyboards.each { |sb| | |
header << "" | |
header << "// #{sb.name_with_language}" | |
if sb.reuse_identifiers.count > 0 | |
header << "" | |
header << "FOUNDATION_EXPORT const struct #{sb.name_with_language}_ReuseIdentifiers {" | |
sb.reuse_identifiers.each { |identifier| | |
header << " __unsafe_unretained NSString *#{identifier};" | |
} | |
header << "} #{sb.name_with_language}_ReuseIdentifiers;" | |
end | |
if sb.segue_identifiers.count > 0 | |
header << "" | |
header << "FOUNDATION_EXPORT const struct #{sb.name_with_language}_SegueIdentifiers {" | |
sb.segue_identifiers.each { |identifier| | |
header << " __unsafe_unretained NSString *#{identifier};" | |
} | |
header << "} #{sb.name_with_language}_SegueIdentifiers;" | |
end | |
if sb.storyboard_identifiers.count > 0 | |
header << "" | |
header << "FOUNDATION_EXPORT const struct #{sb.name_with_language}_StoryboardIdentifiers {" | |
sb.storyboard_identifiers.each { |identifier| | |
header << " __unsafe_unretained NSString *#{identifier};" | |
} | |
header << "} #{sb.name_with_language}_StoryboardIdentifiers;" | |
end | |
} | |
header << "" | |
File.write self.header_file_path, header.join($INPUT_RECORD_SEPARATOR) | |
end | |
def create_implementation_file | |
impl = [] | |
impl << "// This file was generated by a run script. Do not edit." | |
impl << "" | |
impl << "#import \"#{@file_name}.h\"" | |
@storyboards.sort! { |l,r| l.name_with_language <=> r.name_with_language } | |
@storyboards.each { |sb| | |
impl << "" | |
impl << "// #{sb.name_with_language}" | |
if sb.reuse_identifiers.count > 0 | |
impl << "" | |
impl << "const struct #{sb.name_with_language}_ReuseIdentifiers #{sb.name_with_language}_ReuseIdentifiers = {" | |
sb.reuse_identifiers.each { |identifier| | |
impl << " .#{identifier} = @\"#{identifier}\"," | |
} | |
impl << "};" | |
end | |
if sb.segue_identifiers.count > 0 | |
impl << "" | |
impl << "const struct #{sb.name_with_language}_SegueIdentifiers #{sb.name_with_language}_SegueIdentifiers = {" | |
sb.segue_identifiers.each { |identifier| | |
impl << " .#{identifier} = @\"#{identifier}\"," | |
} | |
impl << "};" | |
end | |
if sb.storyboard_identifiers.count > 0 | |
impl << "" | |
impl << "const struct #{sb.name_with_language}_StoryboardIdentifiers #{sb.name_with_language}_StoryboardIdentifiers = {" | |
sb.storyboard_identifiers.each { |identifier| | |
impl << " .#{identifier} = @\"#{identifier}\"," | |
} | |
impl << "};" | |
end | |
} | |
impl << "" | |
File.write self.implementation_file_path, impl.join($INPUT_RECORD_SEPARATOR) | |
end | |
def create_swift_file | |
lines = [] | |
lines << "// This file was generated by a run script. Do not edit." | |
lines << "" | |
lines << "import Foundation" | |
@storyboards.sort! { |l,r| l.name_with_language <=> r.name_with_language } | |
@storyboards.each { |sb| | |
lines << "" | |
lines << "// #{sb.name_with_language}" | |
lines << "" | |
structName = sb.name_with_language | |
structName += "_" if !sb.language.empty? | |
lines << "struct #{structName}Identifiers {" | |
if sb.reuse_identifiers.count > 0 | |
lines << "" | |
lines << " enum Reuse : String {" | |
sb.reuse_identifiers.each { |identifier| | |
lines << " case #{identifier} = \"#{identifier}\"" | |
} | |
lines << " }" | |
end | |
if sb.segue_identifiers.count > 0 | |
lines << "" | |
lines << " enum Segue : String {" | |
sb.segue_identifiers.each { |identifier| | |
lines << " case #{identifier} = \"#{identifier}\"" | |
} | |
lines << " }" | |
end | |
if sb.storyboard_identifiers.count > 0 | |
lines << "" | |
lines << " enum ViewController : String {" | |
sb.storyboard_identifiers.each { |identifier| | |
lines << " case #{identifier} = \"#{identifier}\"" | |
} | |
lines << " }" | |
end | |
lines << "}" # end struct | |
} | |
lines << "" | |
File.write self.swift_file_path, lines.join($INPUT_RECORD_SEPARATOR) | |
end | |
end | |
storyboards = Storyboard.find_storyboard_files_in_path(project_dir) | |
if storyboards.count > 0 | |
generator = SourceFileGenerator.new(output_path, "#{class_prefix}StoryboardIdentifiers", storyboards) | |
if format_as_swift | |
generator.create_swift_file | |
else | |
generator.create_header_file | |
generator.create_implementation_file | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment