ccios 4.1.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/CHANGELOG.md +35 -0
  4. data/Gemfile.lock +34 -15
  5. data/MAINTAINER.md +8 -0
  6. data/README.md +188 -56
  7. data/ccios.gemspec +2 -2
  8. data/lib/ccios/argument_template_parameter.rb +33 -0
  9. data/lib/ccios/code_templater.rb +24 -8
  10. data/lib/ccios/config.rb +41 -91
  11. data/lib/ccios/file_creator.rb +37 -24
  12. data/lib/ccios/file_template_definition.rb +95 -0
  13. data/lib/ccios/flag_template_parameter.rb +17 -0
  14. data/lib/ccios/group_template_definition.rb +54 -0
  15. data/lib/ccios/pbxproj_parser.rb +4 -55
  16. data/lib/ccios/snippet_template_definition.rb +27 -0
  17. data/lib/ccios/template_definition.rb +116 -0
  18. data/lib/ccios/templates/{coordinator.mustache → Coordinator/coordinator.mustache} +5 -2
  19. data/lib/ccios/templates/Coordinator/template.yml +19 -0
  20. data/lib/ccios/templates/{interactor_implementation.mustache → Interactor/interactor_implementation.mustache} +2 -2
  21. data/lib/ccios/templates/Interactor/template.yml +24 -0
  22. data/{templates_library/async → lib/ccios/templates/Presenter}/dependency_provider.mustache +6 -2
  23. data/lib/ccios/templates/{presenter_implementation.mustache → Presenter/presenter_implementation.mustache} +4 -1
  24. data/lib/ccios/templates/Presenter/template.yml +55 -0
  25. data/lib/ccios/templates/{view_contract.mustache → Presenter/view_contract.mustache} +2 -1
  26. data/lib/ccios/templates/{view_controller.mustache → Presenter/view_controller.mustache} +4 -0
  27. data/{templates_library/async/repository.mustache → lib/ccios/templates/Presenter/view_model.mustache} +2 -3
  28. data/lib/ccios/templates/Presenter/view_model_mapper.mustache +16 -0
  29. data/lib/ccios/templates/Repository/template.yml +25 -0
  30. data/lib/ccios/templates_loader.rb +31 -0
  31. data/lib/ccios.rb +65 -43
  32. data/templates_library/async/Coordinator/template.yml +20 -0
  33. data/{lib/ccios/templates → templates_library/async/Presenter}/presenter.mustache +2 -0
  34. data/templates_library/async/Presenter/template.yml +49 -0
  35. metadata +40 -34
  36. data/lib/ccios/coordinator_generator.rb +0 -18
  37. data/lib/ccios/interactor_generator.rb +0 -33
  38. data/lib/ccios/presenter_generator.rb +0 -71
  39. data/lib/ccios/repository_generator.rb +0 -44
  40. data/templates_library/async/interactor.mustache +0 -13
  41. data/templates_library/async/interactor_assembly.mustache +0 -5
  42. data/templates_library/async/interactor_implementation.mustache +0 -22
  43. data/templates_library/async/repository_assembly.mustache +0 -6
  44. data/templates_library/async/repository_implementation.mustache +0 -20
  45. /data/lib/ccios/templates/{interactor.mustache → Interactor/interactor.mustache} +0 -0
  46. /data/lib/ccios/templates/{interactor_assembly.mustache → Interactor/interactor_assembly.mustache} +0 -0
  47. /data/{templates_library/async → lib/ccios/templates/Presenter}/presenter.mustache +0 -0
  48. /data/lib/ccios/templates/{presenter_assembly.mustache → Presenter/presenter_assembly.mustache} +0 -0
  49. /data/lib/ccios/templates/{repository.mustache → Repository/repository.mustache} +0 -0
  50. /data/lib/ccios/templates/{repository_assembly.mustache → Repository/repository_assembly.mustache} +0 -0
  51. /data/lib/ccios/templates/{repository_implementation.mustache → Repository/repository_implementation.mustache} +0 -0
  52. /data/templates_library/async/{coordinator.mustache → Coordinator/coordinator.mustache} +0 -0
  53. /data/{lib/ccios/templates → templates_library/async/Presenter}/dependency_provider.mustache +0 -0
  54. /data/templates_library/async/{presenter_assembly.mustache → Presenter/presenter_assembly.mustache} +0 -0
  55. /data/templates_library/async/{presenter_implementation.mustache → Presenter/presenter_implementation.mustache} +0 -0
  56. /data/templates_library/async/{view_contract.mustache → Presenter/view_contract.mustache} +0 -0
  57. /data/templates_library/async/{view_controller.mustache → Presenter/view_controller.mustache} +0 -0
data/lib/ccios/config.rb CHANGED
@@ -2,11 +2,12 @@ require 'yaml'
2
2
 
3
3
  class Config
4
4
 
5
- attr_reader :app, :core, :data, :templates
5
+ attr_reader :variables, :templates_collection
6
6
 
7
7
  def self.parse(source_path)
8
8
  if File.exist?(source_path)
9
9
  config = YAML.load_file(source_path)
10
+ raise "Invalid config file" unless config.is_a?(Hash)
10
11
  self.new config, source_path
11
12
  else
12
13
  puts "File #{source_path} does not exist. Using default config."
@@ -14,120 +15,69 @@ class Config
14
15
  end
15
16
  end
16
17
 
17
- def self.default_config_hash
18
- project = "*.xcodeproj"
19
- {
20
- "app" => {
21
- "project" => project,
22
- "presenter" => {"group" => "Classes/App"},
23
- "coordinator" => {"group" => "Classes/Coordinator"}
24
- },
25
- "core" => {
26
- "project" => project,
27
- "interactor" => {"group" => "Classes/Core/Interactor"},
28
- "repository" => {"group" => "Classes/Core/Data"}
29
- },
30
- "data" => {
31
- "project" => project,
32
- "repository" => {"group" => "Classes/Data"}
33
- },
34
- "templates" => self.default_templates_hash
35
- }
36
- end
37
-
38
18
  def self.default
39
19
  self.new default_config_hash
40
20
  end
41
21
 
42
- def self.default_templates_hash
43
- { "path" => File.join(File.dirname(__FILE__), "templates") }
22
+ def self.default_config_hash
23
+ {}
44
24
  end
45
25
 
46
26
  def initialize(config_hash, source_path = nil)
47
- @source_path = source_path
48
- validate config_hash
49
- @app = AppConfig.new config_hash["app"]
50
- @core = CoreConfig.new config_hash["core"]
51
- @data = DataConfig.new config_hash["data"]
52
- if config_hash["templates"].nil?
53
- @templates = TemplatesConfig.new Config.default_templates_hash
54
- else
55
- @templates = TemplatesConfig.new config_hash["templates"]
27
+ @variables = config_hash["variables"] || {}
28
+ @templates_collection = config_hash["templates_collection"] || nil
29
+ @templates_config = {}
30
+
31
+ raise "Invalid \"templates_collection\" in config, should be a string" unless @templates_collection.is_a?(String) || @templates_collection.nil?
32
+
33
+ templates_config = config_hash["templates_config"] || {}
34
+ raise "Invalid \"templates_config\" in configuration, it should be a dictionary" unless templates_config.is_a?(Hash)
35
+ templates_config.each do |key, hash|
36
+ raise "Invalid template configuration for \"#{key}\"" unless hash.is_a?(Hash)
37
+ template_config = TemplateConfig.new(hash)
38
+ @templates_config[key] = template_config
56
39
  end
57
40
  end
58
41
 
59
- def validate(hash)
60
- validate_path hash, "app.project"
61
- validate_path hash, "app.presenter.group"
62
- validate_path hash, "app.coordinator.group"
63
-
64
- validate_path hash, "core.project"
65
- validate_path hash, "core.interactor.group"
66
- validate_path hash, "core.repository.group"
67
-
68
- validate_path hash, "data.project"
69
- validate_path hash, "data.repository.group"
42
+ def variables_for_template(template)
43
+ template_config = @templates_config[template.name] || TemplateConfig.new({})
44
+ @variables.merge(template.variables).merge(template_config.variables)
70
45
  end
71
46
 
72
- def validate_path(hash, path)
73
- components = path.split(".")
74
- keys = []
75
- components.each do |component|
76
- hash = hash[component]
77
- keys << component
78
- if hash.nil?
79
- message = "Key \"#{keys.join(".")}\" is missing"
80
- message += " in #{@source_path}" unless @source_path.nil?
81
- raise message
82
- end
83
- end
47
+ def variables_for_template_element(template, element_name, element_default_variables = {})
48
+ template_config = @templates_config[template.name] || TemplateConfig.new({})
49
+ element_config = template_config.element_configuration_for(element_name)
50
+ template_variables = @variables.merge(template.variables).merge(template_config.variables)
51
+ template_variables.merge(element_default_variables).merge(element_config.variables)
84
52
  end
85
53
  end
86
54
 
87
- class AppConfig
88
- attr_reader :project, :target, :presenter, :coordinator
55
+ class TemplateConfig
89
56
 
90
- def initialize(hash)
91
- @project = hash["project"]
92
- @target = hash["target"]
93
- @presenter = ObjectConfig.new hash["presenter"]
94
- @coordinator = ObjectConfig.new hash["coordinator"]
95
- end
96
- end
97
-
98
- class CoreConfig
99
- attr_reader :project, :target, :interactor, :repository
57
+ attr_reader :variables
100
58
 
101
59
  def initialize(hash)
102
- @project = hash["project"]
103
- @target = hash["target"]
104
- @interactor = ObjectConfig.new hash["interactor"]
105
- @repository = ObjectConfig.new hash["repository"]
60
+ @variables = hash["variables"] || {}
61
+ @template_element_config = {}
62
+
63
+ elements_variables = hash["elements_variables"] || {}
64
+ raise "Invalid configuration, \"elements_variables\" should be a dictionary" unless elements_variables.is_a?(Hash)
65
+ elements_variables.each do |key, hash|
66
+ raise "Invalid element variable configuration for \"#{key}\"" unless hash.is_a?(Hash)
67
+ @template_element_config[key] = TemplateElementConfig.new(hash)
68
+ end
106
69
  end
107
- end
108
70
 
109
- class DataConfig
110
- attr_reader :project, :target, :repository
111
-
112
- def initialize(hash)
113
- @project = hash["project"]
114
- @target = hash["target"]
115
- @repository = ObjectConfig.new hash["repository"]
71
+ def element_configuration_for(element)
72
+ @template_element_config[element] || TemplateConfig.new({})
116
73
  end
117
74
  end
118
75
 
119
- class ObjectConfig
120
- attr_reader :group
76
+ class TemplateElementConfig
121
77
 
122
- def initialize(hash)
123
- @group = hash["group"]
124
- end
125
- end
126
-
127
- class TemplatesConfig
128
- attr_reader :path
78
+ attr_reader :variables
129
79
 
130
80
  def initialize(hash)
131
- @path = hash["path"]
81
+ @variables = hash
132
82
  end
133
- end
83
+ end
@@ -1,6 +1,7 @@
1
1
  require_relative 'code_templater'
2
2
  require 'fileutils'
3
3
  require 'logger'
4
+ require 'xcodeproj'
4
5
 
5
6
  class Xcodeproj::Project::Object::PBXGroup
6
7
 
@@ -14,6 +15,13 @@ class Xcodeproj::Project::Object::PBXGroup
14
15
  end
15
16
  end
16
17
 
18
+ class Xcodeproj::Project
19
+
20
+ def project_name_from_path
21
+ File.basename(@path, File.extname(@path))
22
+ end
23
+ end
24
+
17
25
  class FileCreator
18
26
 
19
27
  def self.logger
@@ -24,40 +32,55 @@ class FileCreator
24
32
  FileCreator.logger
25
33
  end
26
34
 
27
- def initialize(options = {}, config)
28
- @options = options
29
- @config = config
30
- end
31
-
32
- def templater_options(target)
35
+ def templater_options(targets, project)
33
36
  defaults = {
34
- project_name: target.display_name,
35
37
  full_username: git_username,
36
38
  date: DateTime.now.strftime("%d/%m/%Y"),
37
39
  }
38
- defaults.merge(@options)
40
+ if targets.count == 1
41
+ defaults["project_name"] = targets[0].display_name
42
+ else
43
+ defaults["project_name"] = project.project_name_from_path
44
+ end
45
+ defaults
39
46
  end
40
47
 
41
48
  def git_username
42
49
  `git config user.name`.strip
43
50
  end
44
51
 
45
- def create_file(prefix, suffix, group, target)
46
- file_path = File.join(group.real_path, prefix + suffix + '.swift')
52
+ def get_unknown_template_tags_for(template_path)
53
+ tags = CodeTemplater.new.get_unknown_context_keys_for_template(template_path)
54
+ tags.subtract(Set["project_name", "full_username", "date"])
55
+ tags
56
+ end
57
+
58
+ def create_file_using_template_path(template_path, generated_filename, group, targets, project, context)
59
+ file_path = File.join(group.real_path, generated_filename)
47
60
 
48
61
  raise "File #{file_path} already exists" if File.exist?(file_path)
49
62
  dirname = File.dirname(file_path)
50
63
  FileUtils.mkdir_p dirname unless File.directory?(dirname)
51
64
  file = File.new(file_path, 'w')
52
65
 
53
- templater_options = templater_options(target)
54
- code_templater = CodeTemplater.new(templater_options, @config.templates.path)
55
- file_content = code_templater.content_for_suffix(prefix, suffix)
66
+ context = context.merge(templater_options(targets, project))
67
+ file_content = CodeTemplater.new.render_file_content_from_template(template_path, generated_filename, context)
68
+
56
69
  file.puts(file_content)
57
70
 
58
71
  file.close
59
72
  file_ref = group.new_reference(file_path)
60
- target.add_file_references([file_ref])
73
+ targets.each do |target|
74
+ target.add_file_references([file_ref])
75
+ end
76
+ end
77
+
78
+ def print_file_content_using_template(filename, template_path, context)
79
+ file_content = CodeTemplater.new.render_file_content_from_template(template_path, filename, context)
80
+ Mustache.render(File.read(template_path), context)
81
+
82
+ logger.info "Add this snippet to #{filename}"
83
+ logger.info file_content
61
84
  end
62
85
 
63
86
  def create_empty_directory(group)
@@ -68,16 +91,6 @@ class FileCreator
68
91
  FileUtils.touch(git_keep_path) if Dir.empty?(dirname)
69
92
  end
70
93
 
71
- def print_file_content(prefix, suffix)
72
- file_name = suffix + '.swift'
73
-
74
- code_templater = CodeTemplater.new(@options, @config.templates.path)
75
- template = code_templater.content_for_suffix(prefix, suffix)
76
-
77
- logger.info "Add this snippet to #{file_name}"
78
- logger.info template
79
- end
80
-
81
94
  private
82
95
 
83
96
  def self.create_logger
@@ -0,0 +1,95 @@
1
+ require_relative 'code_templater'
2
+ require_relative 'file_creator'
3
+ require_relative 'pbxproj_parser'
4
+
5
+ class FileTemplateDefinition
6
+ def initialize(file_template_definition_hash)
7
+ @name = file_template_definition_hash["name"]
8
+ @path = file_template_definition_hash["file"]
9
+ @template = file_template_definition_hash["template"]
10
+ @variables = file_template_definition_hash["variables"] || {}
11
+ end
12
+
13
+ def validate(parser, project, context, template_definition, config)
14
+
15
+ merged_variables = config.variables_for_template_element(template_definition, @name, @variables)
16
+
17
+ code_templater = CodeTemplater.new
18
+ expected_context_keys = template_definition.provided_context_keys
19
+ pathTags = code_templater.get_unknown_context_keys_for_string(@path)
20
+ pathTags.each do |tag|
21
+ raise "Unknown parameter \"#{tag}\" in path \"#{@path}\"" unless expected_context_keys.include?(tag)
22
+ end
23
+
24
+ file_path = code_templater.render_string(@path, context)
25
+ raise "File #{file_path} already exists" if File.exist?(file_path)
26
+
27
+ file_creator = FileCreator.new
28
+ contentTags = file_creator.get_unknown_template_tags_for(template_definition.template_source_file(@template))
29
+ contentTags.each do |tag|
30
+ raise "Unknown parameter \"#{tag}\" in template \"#{@template}\"" unless expected_context_keys.include?(tag)
31
+ end
32
+
33
+ base_path = merged_variables["base_path"]
34
+ raise "Missing base_path variable" if base_path.nil?
35
+
36
+ base_group = project[base_path]
37
+ raise "Base path \"#{base_path}\" is missing" if base_group.nil?
38
+
39
+ target_name = merged_variables["target"]
40
+ if target_name.is_a?(String) || target_name.nil?
41
+ target = parser.target_for(project, target_name)
42
+ raise "Unable to find target \"#{target_name}\"" if target.nil?
43
+ elsif target_name.is_a?(Array)
44
+ target_name.each do |target_name|
45
+ target = parser.target_for(project, target_name)
46
+ raise "Unable to find target \"#{target_name}\"" if target.nil?
47
+ end
48
+ else
49
+ raise "Invalid target in template #{@name}"
50
+ end
51
+
52
+ end
53
+
54
+ def generate(parser, project, context, template_definition, config)
55
+ merged_variables = config.variables_for_template_element(template_definition, @name, @variables)
56
+
57
+ base_path = merged_variables["base_path"]
58
+ base_group = project[base_path]
59
+ file_path = CodeTemplater.new.render_string(@path, context)
60
+
61
+ intermediates_groups = file_path.split("/")[0...-1]
62
+ generated_filename = file_path.split("/")[-1]
63
+
64
+ group = base_group
65
+ associate_path_to_group = !base_group.path.nil?
66
+
67
+ intermediates_groups.each do |group_name|
68
+ new_group_path = File.join(group.real_path, group_name)
69
+ existing_group = group.groups.find { |g| g.display_name == group_name }
70
+ group = existing_group || group.pf_new_group(
71
+ associate_path_to_group: associate_path_to_group,
72
+ name: group_name,
73
+ path: new_group_path
74
+ )
75
+ end
76
+
77
+ target_name = merged_variables["target"]
78
+
79
+ targets = []
80
+ if target_name.is_a?(String) || target_name.nil?
81
+ targets = [parser.target_for(project, target_name)]
82
+ elsif target_name.is_a?(Array)
83
+ targets = target_name.map { |name| parser.target_for(project, name) }
84
+ end
85
+
86
+ FileCreator.new.create_file_using_template_path(
87
+ template_definition.template_source_file(@template),
88
+ generated_filename,
89
+ group,
90
+ targets,
91
+ project,
92
+ context
93
+ )
94
+ end
95
+ end
@@ -0,0 +1,17 @@
1
+ class FlagTemplateParameter
2
+ attr_reader :name, :short_name, :description, :template_variable_name
3
+
4
+ def initialize(parameter_template_definition_hash)
5
+ @name = parameter_template_definition_hash["flag"]
6
+ @short_name = parameter_template_definition_hash["short_name"]
7
+ @description = parameter_template_definition_hash["description"] || ""
8
+ @template_variable_name = parameter_template_definition_hash["template_variable_name"] || @name
9
+
10
+ raise "Missing flag name" if @name.nil? || @name.empty?
11
+ raise "Invalid flag template_variable_name for #{@name}" if @template_variable_name.nil? || template_variable_name.empty?
12
+ end
13
+
14
+ def provided_context_keys
15
+ [@template_variable_name]
16
+ end
17
+ end
@@ -0,0 +1,54 @@
1
+ require_relative 'code_templater'
2
+ require_relative 'file_creator'
3
+ require_relative 'pbxproj_parser'
4
+
5
+ class GroupTemplateDefinition
6
+ def initialize(group_template_definition_hash)
7
+ @name = group_template_definition_hash["name"]
8
+ @path = group_template_definition_hash["group"]
9
+ @template = group_template_definition_hash["path"]
10
+ @variables = group_template_definition_hash["variables"] || {}
11
+ end
12
+
13
+ def validate(parser, project, context, template_definition, config)
14
+ merged_variables = config.variables_for_template_element(template_definition, @name, @variables)
15
+
16
+ code_templater = CodeTemplater.new
17
+ pathTags = code_templater.get_unknown_context_keys_for_string(@path)
18
+ pathTags.each do |tag|
19
+ raise "Unknown parameter \"#{tag}\" in path \"#{@path}\"" if context[tag].nil?
20
+ end
21
+
22
+ base_path = merged_variables["base_path"]
23
+ raise "Missing base_path variable" if base_path.nil?
24
+
25
+ base_group = project[base_path]
26
+ raise "Base path \"#{base_path}\" is missing" if base_group.nil?
27
+ end
28
+
29
+ def generate(parser, project, context, template_definition, config)
30
+ merged_variables = config.variables_for_template_element(template_definition, @name, @variables)
31
+
32
+ base_path = merged_variables["base_path"]
33
+ base_group = project[base_path]
34
+ group_path = CodeTemplater.new.render_string(@path, context)
35
+
36
+ group_path = group_path.split("/")
37
+
38
+ group = base_group
39
+ associate_path_to_group = !base_group.path.nil?
40
+
41
+ group_path.each do |group_name|
42
+ new_group_path = File.join(group.real_path, group_name)
43
+ existing_group = group.groups.find { |g| g.display_name == group_name }
44
+ group = existing_group || group.pf_new_group(
45
+ associate_path_to_group: associate_path_to_group,
46
+ name: group_name,
47
+ path: new_group_path
48
+ )
49
+ end
50
+
51
+ file_creator = FileCreator.new
52
+ file_creator.create_empty_directory(group)
53
+ end
54
+ end
@@ -11,63 +11,12 @@ class PBXProjParser
11
11
  @projects = {}
12
12
  end
13
13
 
14
- def app_project
15
- project_for(@config.app.project)
16
- end
17
-
18
- def core_project
19
- project_for(@config.core.project)
20
- end
21
-
22
- def data_project
23
- project_for(@config.data.project)
24
- end
25
-
26
- def presenter_group
27
- path = @config.app.presenter.group
28
- app_project[path]
29
- end
30
-
31
- def coordinator_group
32
- path = @config.app.coordinator.group
33
- app_project[path]
34
- end
35
-
36
- def interactor_group
37
- path = @config.core.interactor.group
38
- core_project[path]
39
- end
40
-
41
- def repository_core_group
42
- path = @config.core.repository.group
43
- core_project[path]
44
- end
45
-
46
- def repository_data_group
47
- path = @config.data.repository.group
48
- data_project[path]
49
- end
50
-
51
- def app_target
52
- target_for(app_project, @config.app.target)
53
- end
54
-
55
- def core_target
56
- target_for(core_project, @config.core.target)
57
- end
58
-
59
- def data_target
60
- target_for(data_project, @config.data.target)
61
- end
62
-
63
14
  def save
64
- app_project.save
65
- core_project.save
66
- data_project.save
15
+ @projects.each do |path, value|
16
+ value.save
17
+ end
67
18
  end
68
19
 
69
- private
70
-
71
20
  def project_for(path)
72
21
  module_project_path = File.join(source_path, path)
73
22
  resolved_module_project_path = Dir.glob(module_project_path).first
@@ -78,7 +27,7 @@ class PBXProjParser
78
27
  end
79
28
 
80
29
  def target_for(project, target_name)
81
- if target_name.blank?
30
+ if target_name.blank? || target_name.nil?
82
31
  project.targets.find { |t| t.product_type == "com.apple.product-type.application" }
83
32
  else
84
33
  project.targets.find { |t| t.name == target_name }
@@ -0,0 +1,27 @@
1
+ require_relative 'file_creator'
2
+
3
+ class SnippetTemplateDefinition
4
+ def initialize(snippet_template_definition_hash)
5
+ @name = snippet_template_definition_hash["name"]
6
+ @template = snippet_template_definition_hash["template"]
7
+ end
8
+
9
+ def validate(template_definition)
10
+ expected_context_keys = template_definition.provided_context_keys
11
+ file_creator = FileCreator.new
12
+ contentTags = file_creator.get_unknown_template_tags_for(template_definition.template_source_file(@template))
13
+ contentTags.each do |tag|
14
+ raise "Unknown parameter \"#{tag}\" in template \"#{@template}\"" unless expected_context_keys.include?(tag)
15
+ end
16
+ end
17
+
18
+ def generate(context, template_definition)
19
+
20
+ file_creator = FileCreator.new
21
+ file_creator.print_file_content_using_template(
22
+ @name,
23
+ template_definition.template_source_file(@template),
24
+ context
25
+ )
26
+ end
27
+ end
@@ -0,0 +1,116 @@
1
+ require 'yaml'
2
+
3
+ require_relative 'file_creator'
4
+ require_relative 'pbxproj_parser'
5
+ require_relative 'argument_template_parameter'
6
+ require_relative 'flag_template_parameter'
7
+ require_relative 'file_template_definition'
8
+ require_relative 'group_template_definition'
9
+ require_relative 'snippet_template_definition'
10
+
11
+ class TemplateDefinition
12
+
13
+ attr_reader :name, :description, :template_path, :template_file_source, :parameters, :variables
14
+
15
+ def self.parse(template_path)
16
+ template_definition = File.join(template_path, 'template.yml')
17
+ if File.exist?(template_definition)
18
+ template_definition = YAML.load_file(template_definition)
19
+ self.new template_definition, template_path
20
+ else
21
+ puts "Template #{template_path} is invalid: file #{template_definition} not found."
22
+ nil
23
+ end
24
+ end
25
+
26
+ def initialize(template_definition_hash, template_path)
27
+ @template_definition_hash = template_definition_hash
28
+ @template_path = template_path
29
+
30
+ @name = template_definition_hash["name"]
31
+ @description = template_definition_hash["description"] || ""
32
+ @variables = template_definition_hash["variables"] || {}
33
+
34
+ @parameters = template_definition_hash["parameters"].map { |hash|
35
+ next ArgumentTemplateParameter.new(hash) unless hash["argument"].nil?
36
+ next FlagTemplateParameter.new(hash) unless hash["flag"].nil?
37
+ }.compact
38
+
39
+ @generated_elements = template_definition_hash["generated_elements"].map { |hash|
40
+ next FileTemplateDefinition.new(hash) unless hash["file"].nil?
41
+ next GroupTemplateDefinition.new(hash) unless hash["group"].nil?
42
+ next nil
43
+ }.compact
44
+
45
+ if template_definition_hash["code_snippets"].nil?
46
+ @snippets = []
47
+ else
48
+ @snippets = template_definition_hash["code_snippets"].map { |hash|
49
+ SnippetTemplateDefinition.new(hash)
50
+ }
51
+ end
52
+
53
+ @template_file_source = template_definition_hash["template_file_source"] || {}
54
+ end
55
+
56
+ def validate(parser, options, config)
57
+
58
+ raise "Error: missing name in template" if @name.nil?
59
+ raise "Error: invalid template name" unless @name.is_a? String
60
+
61
+ merged_variables = config.variables_for_template(self)
62
+ project_path = merged_variables["project"]
63
+
64
+ project = parser.project_for(project_path)
65
+ raise "Error: Unable to find project \"#{project_path}\"" if project.nil?
66
+
67
+ @template_file_source.each do |file_template_name, path|
68
+ raise "Missing template source file for \"#{file_template_name}\"" unless File.exist?(self.template_source_file(file_template_name))
69
+ end
70
+
71
+ options = agrument_transformed_options(options)
72
+
73
+ @generated_elements.each do |generated_element|
74
+ generated_element.validate(parser, project, options, self, config)
75
+ end
76
+
77
+ @snippets.each do |snippet|
78
+ snippet.validate(self)
79
+ end
80
+ end
81
+
82
+ def template_source_file(name)
83
+ raise "Unknown template file #{name}" if @template_file_source[name].nil?
84
+ File.join(@template_path, @template_file_source[name])
85
+ end
86
+
87
+ def provided_context_keys
88
+ @parameters.flat_map { |p| p.provided_context_keys }.to_set
89
+ end
90
+
91
+ def generate(parser, options, config)
92
+
93
+ options = agrument_transformed_options(options)
94
+
95
+ merged_variables = config.variables_for_template(self)
96
+ project_path = merged_variables["project"]
97
+
98
+ project = parser.project_for project_path
99
+
100
+ @generated_elements.each do |element|
101
+ element.generate(parser, project, options, self, config)
102
+ end
103
+
104
+ @snippets.each do |snippet|
105
+ snippet.generate(options, self)
106
+ end
107
+ end
108
+
109
+ def agrument_transformed_options(options)
110
+ @parameters.select { |p| p.is_a? ArgumentTemplateParameter }.each do |argument|
111
+ options = argument.update_context(options)
112
+ end
113
+ options
114
+ end
115
+
116
+ end
@@ -10,6 +10,7 @@ import Foundation
10
10
  import ADCoordinator
11
11
 
12
12
  {{#generate_delegate}}
13
+ @MainActor
13
14
  protocol {{name}}CoordinatorDelegate: AnyObject {
14
15
 
15
16
  }
@@ -23,8 +24,10 @@ class {{name}}Coordinator: Coordinator {
23
24
  private let dependencyProvider: ApplicationDependencyProvider
24
25
  private unowned var navigationController: UINavigationController
25
26
 
26
- init(navigationController: UINavigationController,
27
- dependencyProvider: ApplicationDependencyProvider) {
27
+ init(
28
+ navigationController: UINavigationController,
29
+ dependencyProvider: ApplicationDependencyProvider
30
+ ) {
28
31
  self.navigationController = navigationController
29
32
  self.dependencyProvider = dependencyProvider
30
33
  }