ccios 5.0.0 → 5.2.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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +19 -0
- data/Gemfile.lock +35 -16
- data/MAINTAINER.md +12 -0
- data/README.md +20 -2
- data/ccios.gemspec +3 -3
- data/lib/ccios/file_creator.rb +26 -18
- data/lib/ccios/file_template_definition.rb +53 -29
- data/lib/ccios/group_template_definition.rb +6 -19
- data/lib/ccios/pbxproj_parser.rb +2 -2
- data/lib/ccios/template_definition.rb +20 -6
- data/lib/ccios/templates/Coordinator/coordinator.mustache +5 -2
- data/lib/ccios/templates/Coordinator/template.yml +0 -1
- data/lib/ccios/templates/Interactor/interactor_implementation.mustache +2 -2
- data/lib/ccios/templates/Interactor/template.yml +0 -1
- data/lib/ccios/templates/Presenter/dependency_provider.mustache +6 -2
- data/lib/ccios/templates/Presenter/presenter.mustache +2 -0
- data/lib/ccios/templates/Presenter/presenter_implementation.mustache +4 -1
- data/lib/ccios/templates/Presenter/template.yml +9 -3
- data/lib/ccios/templates/Presenter/view_contract.mustache +2 -1
- data/lib/ccios/templates/Presenter/view_controller.mustache +4 -0
- data/lib/ccios/templates/Presenter/view_model.mustache +12 -0
- data/lib/ccios/templates/Presenter/view_model_mapper.mustache +16 -0
- data/lib/ccios/templates/Repository/template.yml +0 -1
- data/lib/ccios/xcode_group_representation.rb +107 -0
- metadata +10 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27b359e8339dcd511d85488eb93f75d19e7b03bc6ed7cceedebdd721c3b9ad03
|
4
|
+
data.tar.gz: db07b4baa0b8143fcec3f70c3ecbd45b9e4a26b1885659128da67a52ffb1afc3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 25e62f91e331fe7b2e1e8b58dd1e44559faefe40be02b61a8d3858a0ba174618af52d897d9e87fa2b91b7df21e82a6130c8891d51bb0bc706764142c2b8916a4
|
7
|
+
data.tar.gz: c924d07dc088ca07efddc97de3222411f8fa564935b28e971480856bce1c08f88e3323134725f721d385e061980c62d50083057d9291a55c6c399db5b4ec0ca2
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.3.0
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,25 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
|
5
5
|
## [Unreleased]
|
6
6
|
|
7
|
+
## [5.2.0]
|
8
|
+
|
9
|
+
### Added
|
10
|
+
|
11
|
+
- Add support for Swift Packages and Xcode 16 synchronized folders
|
12
|
+
- Add new optional variable nammed "project_type" which accepts 2 values: "xcode" and "filesystem". When missing ccios use "xcode" by default.
|
13
|
+
- When "project_type" is set to "filesystem" ccios will not try to update a pbxproj and will only generate files.
|
14
|
+
- When "project_type" is set to "filesystem" multi target definition is no longer supported for generated files.
|
15
|
+
- When generating files for an filesystem project, the target name in the header is either: the target defined in the template variables, the target defined in `.ccios.yml`, or it will try to guess the name when using SPM by searching the target name inside the standard naming scheme of: "Sources/<target_name>/".
|
16
|
+
|
17
|
+
## [5.1.0]
|
18
|
+
|
19
|
+
### Changed
|
20
|
+
|
21
|
+
- Target variable is now optional, an empty string or an unset value will use the first target of the project. This change allows templates to not overrides global target settings in `.ccios.yml`
|
22
|
+
- When multiple targets are provided for a file, `{{project_name}}` will now be replaced by the name of the project instead of the name of the first target
|
23
|
+
- `@MainActor` has been added to relevent files in Coordinator and Presenter templates to improve Swift 6 support
|
24
|
+
- dependency provider snippets has been updated to handle Swift 6 issue (see [this issue](https://github.com/Swinject/Swinject/issues/571) for why this is required)
|
25
|
+
|
7
26
|
## [5.0.0]
|
8
27
|
|
9
28
|
This release is an entire rewrite of the templating system, allowing customization of template and settings.
|
data/Gemfile.lock
CHANGED
@@ -1,41 +1,60 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ccios (5.
|
4
|
+
ccios (5.2.0)
|
5
5
|
activesupport (> 4)
|
6
6
|
mustache (~> 1.0)
|
7
|
-
xcodeproj (~> 1.
|
7
|
+
xcodeproj (~> 1.27)
|
8
8
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
CFPropertyList (3.0.
|
12
|
+
CFPropertyList (3.0.7)
|
13
|
+
base64
|
14
|
+
nkf
|
13
15
|
rexml
|
14
|
-
activesupport (
|
15
|
-
|
16
|
+
activesupport (8.0.2)
|
17
|
+
base64
|
18
|
+
benchmark (>= 0.3)
|
19
|
+
bigdecimal
|
20
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
21
|
+
connection_pool (>= 2.2.5)
|
22
|
+
drb
|
16
23
|
i18n (>= 1.6, < 2)
|
24
|
+
logger (>= 1.4.2)
|
17
25
|
minitest (>= 5.1)
|
18
|
-
|
26
|
+
securerandom (>= 0.3)
|
27
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
28
|
+
uri (>= 0.13.1)
|
19
29
|
atomos (0.1.3)
|
30
|
+
base64 (0.3.0)
|
31
|
+
benchmark (0.4.1)
|
32
|
+
bigdecimal (3.2.2)
|
20
33
|
claide (1.1.0)
|
21
34
|
colored2 (3.1.2)
|
22
|
-
concurrent-ruby (1.
|
23
|
-
|
35
|
+
concurrent-ruby (1.3.5)
|
36
|
+
connection_pool (2.5.3)
|
37
|
+
drb (2.2.3)
|
38
|
+
i18n (1.14.7)
|
24
39
|
concurrent-ruby (~> 1.0)
|
25
|
-
|
40
|
+
logger (1.7.0)
|
41
|
+
minitest (5.25.5)
|
26
42
|
mustache (1.1.1)
|
27
|
-
nanaimo (0.
|
28
|
-
|
29
|
-
|
43
|
+
nanaimo (0.4.0)
|
44
|
+
nkf (0.2.0)
|
45
|
+
rake (13.3.0)
|
46
|
+
rexml (3.4.1)
|
47
|
+
securerandom (0.4.1)
|
30
48
|
tzinfo (2.0.6)
|
31
49
|
concurrent-ruby (~> 1.0)
|
32
|
-
|
50
|
+
uri (1.0.3)
|
51
|
+
xcodeproj (1.27.0)
|
33
52
|
CFPropertyList (>= 2.3.3, < 4.0)
|
34
53
|
atomos (~> 0.1.3)
|
35
54
|
claide (>= 1.0.2, < 2.0)
|
36
55
|
colored2 (~> 3.1)
|
37
|
-
nanaimo (~> 0.
|
38
|
-
rexml (
|
56
|
+
nanaimo (~> 0.4.0)
|
57
|
+
rexml (>= 3.3.6, < 4.0)
|
39
58
|
|
40
59
|
PLATFORMS
|
41
60
|
ruby
|
@@ -43,7 +62,7 @@ PLATFORMS
|
|
43
62
|
DEPENDENCIES
|
44
63
|
ccios!
|
45
64
|
minitest (~> 5.11)
|
46
|
-
rake (~>
|
65
|
+
rake (~> 13.2)
|
47
66
|
|
48
67
|
BUNDLED WITH
|
49
68
|
2.4.10
|
data/MAINTAINER.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
## How to release a new version
|
3
|
+
|
4
|
+
- Create the release branch `release/vA.B.C`
|
5
|
+
- Complete the changelog and add the new vertion title
|
6
|
+
- Update the version in ccios.gemspec & run `bundle install`
|
7
|
+
- Create a Pull Request
|
8
|
+
- Once merged, create a tag `A.B.C` on the merged commit
|
9
|
+
- Create release in GitHub
|
10
|
+
- Publish release to RubyGem:
|
11
|
+
- `make build`
|
12
|
+
- `gem push ccios-A.B.C.gem`
|
data/README.md
CHANGED
@@ -137,7 +137,9 @@ templates_collection: ccios/templates
|
|
137
137
|
|
138
138
|
# Global overrides of variables [Optional]
|
139
139
|
variables:
|
140
|
+
project_type: xcode
|
140
141
|
project: Project.xcodeproj
|
142
|
+
target: SomeDefaultTarget
|
141
143
|
|
142
144
|
# Per template variables override
|
143
145
|
templates_config:
|
@@ -220,12 +222,15 @@ parameters:
|
|
220
222
|
# List of templates variables that is used to generate files in an xcode project. [Optional]
|
221
223
|
# Those variables can be overridden in config file, see section "Variable hierarchy" for more informations.
|
222
224
|
variables:
|
225
|
+
# Type of project "filesystem" or "xcode", will be considered as "xcode" if not specified. [Optional]
|
226
|
+
# You want to use "filesystem" if you want to generate files for an SPM project, or if your Xcode project uses the new synchronized group from Xcode 16.
|
227
|
+
project_type: filesystem
|
223
228
|
# The name of the xcode project. "*.xcodeproj" will use the first it finds. [required]
|
224
229
|
project: "*.xcodeproj"
|
225
230
|
# The base path used to generate an element. This variable must be defined once here, or on each elements below.
|
226
231
|
base_path: "path/to/base_group"
|
227
|
-
# The target in which files are added. Can be a string, a list of strings, or an empty string. This variable must be defined once here, or on each elements below. If an empty string is provided, it will use the first target found in the Xcode project.
|
228
|
-
target: ""
|
232
|
+
# The target in which files are added. Can be a string, a list of strings, or an empty string. This variable must be defined once here, or on each elements below. If this variable is not set or if an empty string is provided, it will use the first target found in the Xcode project. If present it will override the global default target. [Optional]
|
233
|
+
target: "SomeTarget"
|
229
234
|
# List of generated elements. [Required]
|
230
235
|
# Each element can be a file (using `file`), or an empty folder (using `group`)
|
231
236
|
generated_elements:
|
@@ -296,3 +301,16 @@ Element will use variables in this order (first in this list is used): (For file
|
|
296
301
|
- Config Template variables
|
297
302
|
- Default templates variables
|
298
303
|
- Config Global variables
|
304
|
+
|
305
|
+
# How to develop
|
306
|
+
|
307
|
+
1. install the gem locally using
|
308
|
+
```bash
|
309
|
+
make install
|
310
|
+
```
|
311
|
+
2. Run use the locally installed ccios gem on your project
|
312
|
+
```bash
|
313
|
+
ccios presenter MyNewPresenterStack
|
314
|
+
```
|
315
|
+
|
316
|
+
Note: ensure that you use the same ruby version when building, installing and running this local version of ccios.
|
data/ccios.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'ccios'
|
3
|
-
s.version = '5.
|
3
|
+
s.version = '5.2.0'
|
4
4
|
s.executables << 'ccios'
|
5
5
|
s.date = '2016-08-03'
|
6
6
|
s.summary = "Clean Code iOS Generator"
|
@@ -12,9 +12,9 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.homepage = 'http://rubygems.org/gems/hola'
|
13
13
|
s.license = 'MIT'
|
14
14
|
s.add_dependency 'activesupport', '> 4'
|
15
|
-
s.add_dependency 'xcodeproj', '~> 1.
|
15
|
+
s.add_dependency 'xcodeproj', '~> 1.27'
|
16
16
|
s.add_dependency "mustache", "~> 1.0"
|
17
17
|
|
18
|
-
s.add_development_dependency 'rake', '~>
|
18
|
+
s.add_development_dependency 'rake', '~> 13.2'
|
19
19
|
s.add_development_dependency 'minitest', '~> 5.11'
|
20
20
|
end
|
data/lib/ccios/file_creator.rb
CHANGED
@@ -3,15 +3,10 @@ require 'fileutils'
|
|
3
3
|
require 'logger'
|
4
4
|
require 'xcodeproj'
|
5
5
|
|
6
|
-
class Xcodeproj::Project
|
7
|
-
|
8
|
-
def
|
9
|
-
|
10
|
-
# When using "Group without folder" we only provide a name
|
11
|
-
new_group(
|
12
|
-
associate_path_to_group ? nil : name,
|
13
|
-
associate_path_to_group ? path : nil
|
14
|
-
)
|
6
|
+
class Xcodeproj::Project
|
7
|
+
|
8
|
+
def project_name_from_path
|
9
|
+
File.basename(@path, File.extname(@path))
|
15
10
|
end
|
16
11
|
end
|
17
12
|
|
@@ -25,12 +20,24 @@ class FileCreator
|
|
25
20
|
FileCreator.logger
|
26
21
|
end
|
27
22
|
|
28
|
-
def templater_options(
|
23
|
+
def templater_options(targets, project)
|
29
24
|
defaults = {
|
30
|
-
project_name: target.display_name,
|
31
25
|
full_username: git_username,
|
32
26
|
date: DateTime.now.strftime("%d/%m/%Y"),
|
33
27
|
}
|
28
|
+
if project.nil?
|
29
|
+
if targets.count == 1
|
30
|
+
defaults["project_name"] = targets[0]
|
31
|
+
else
|
32
|
+
raise "A file outside an xcode project cannot require multiple targets"
|
33
|
+
end
|
34
|
+
else
|
35
|
+
if targets.count == 1
|
36
|
+
defaults["project_name"] = targets[0].display_name
|
37
|
+
else
|
38
|
+
defaults["project_name"] = project.project_name_from_path
|
39
|
+
end
|
40
|
+
end
|
34
41
|
defaults
|
35
42
|
end
|
36
43
|
|
@@ -44,7 +51,7 @@ class FileCreator
|
|
44
51
|
tags
|
45
52
|
end
|
46
53
|
|
47
|
-
def create_file_using_template_path(template_path, generated_filename, group, targets, context)
|
54
|
+
def create_file_using_template_path(template_path, generated_filename, group, targets, project, context)
|
48
55
|
file_path = File.join(group.real_path, generated_filename)
|
49
56
|
|
50
57
|
raise "File #{file_path} already exists" if File.exist?(file_path)
|
@@ -52,16 +59,13 @@ class FileCreator
|
|
52
59
|
FileUtils.mkdir_p dirname unless File.directory?(dirname)
|
53
60
|
file = File.new(file_path, 'w')
|
54
61
|
|
55
|
-
context = context.merge(templater_options(targets
|
62
|
+
context = context.merge(templater_options(targets, project))
|
56
63
|
file_content = CodeTemplater.new.render_file_content_from_template(template_path, generated_filename, context)
|
57
64
|
|
58
65
|
file.puts(file_content)
|
59
66
|
|
60
67
|
file.close
|
61
|
-
|
62
|
-
targets.each do |target|
|
63
|
-
target.add_file_references([file_ref])
|
64
|
-
end
|
68
|
+
group.register_file_to_targets(file_path, targets)
|
65
69
|
end
|
66
70
|
|
67
71
|
def print_file_content_using_template(filename, template_path, context)
|
@@ -72,8 +76,12 @@ class FileCreator
|
|
72
76
|
logger.info file_content
|
73
77
|
end
|
74
78
|
|
75
|
-
def
|
79
|
+
def create_empty_directory_for_group(group)
|
76
80
|
dirname = group.real_path
|
81
|
+
create_empty_directory(dirname)
|
82
|
+
end
|
83
|
+
|
84
|
+
def create_empty_directory(dirname)
|
77
85
|
FileUtils.mkdir_p dirname unless File.directory?(dirname)
|
78
86
|
|
79
87
|
git_keep_path = File.join(dirname, ".gitkeep")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative 'code_templater'
|
2
2
|
require_relative 'file_creator'
|
3
|
-
require_relative '
|
3
|
+
require_relative 'xcode_group_representation'
|
4
4
|
|
5
5
|
class FileTemplateDefinition
|
6
6
|
def initialize(file_template_definition_hash)
|
@@ -33,20 +33,34 @@ class FileTemplateDefinition
|
|
33
33
|
base_path = merged_variables["base_path"]
|
34
34
|
raise "Missing base_path variable" if base_path.nil?
|
35
35
|
|
36
|
-
base_group = project[base_path]
|
37
|
-
raise "Base path \"#{base_path}\" is missing" if base_group.nil?
|
38
|
-
|
39
36
|
target_name = merged_variables["target"]
|
40
|
-
if
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
37
|
+
if project.nil?
|
38
|
+
if target_name.is_a?(String)
|
39
|
+
target = target_name
|
40
|
+
elsif target_name.nil?
|
41
|
+
guessed_name = guess_target_name_from_path(base_path)
|
42
|
+
raise "Unable to guess the target from the base path \"#{base_path}\", please specify the target in your config file" if guessed_name.nil?
|
43
|
+
target = guessed_name
|
44
|
+
elsif target_name.is_a?(Array)
|
45
|
+
raise "A template generating files in an filesystem project type cannot specify multiple targets"
|
46
|
+
else
|
47
|
+
raise "Invalid target in template #{@name}"
|
48
|
+
end
|
49
|
+
else
|
50
|
+
base_group = XcodeGroupRepresentation.findGroup(base_path, project)
|
51
|
+
raise "Base path \"#{base_path}\" is missing" if base_group.nil?
|
52
|
+
|
53
|
+
if target_name.is_a?(String) || target_name.nil?
|
45
54
|
target = parser.target_for(project, target_name)
|
46
55
|
raise "Unable to find target \"#{target_name}\"" if target.nil?
|
56
|
+
elsif target_name.is_a?(Array)
|
57
|
+
target_name.each do |target_name|
|
58
|
+
target = parser.target_for(project, target_name)
|
59
|
+
raise "Unable to find target \"#{target_name}\"" if target.nil?
|
60
|
+
end
|
61
|
+
else
|
62
|
+
raise "Invalid target in template #{@name}"
|
47
63
|
end
|
48
|
-
else
|
49
|
-
raise "Invalid target in template #{@name}"
|
50
64
|
end
|
51
65
|
|
52
66
|
end
|
@@ -55,32 +69,30 @@ class FileTemplateDefinition
|
|
55
69
|
merged_variables = config.variables_for_template_element(template_definition, @name, @variables)
|
56
70
|
|
57
71
|
base_path = merged_variables["base_path"]
|
58
|
-
base_group = project
|
72
|
+
base_group = XcodeGroupRepresentation.findGroup(base_path, project)
|
59
73
|
file_path = CodeTemplater.new.render_string(@path, context)
|
60
74
|
|
61
75
|
intermediates_groups = file_path.split("/")[0...-1]
|
62
76
|
generated_filename = file_path.split("/")[-1]
|
63
77
|
|
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
|
78
|
+
group = base_group.create_groups_if_needed_for_intermediate_groups(intermediates_groups)
|
76
79
|
|
77
80
|
target_name = merged_variables["target"]
|
78
81
|
|
79
82
|
targets = []
|
80
|
-
if
|
81
|
-
|
82
|
-
|
83
|
-
|
83
|
+
if project.nil?
|
84
|
+
if target_name.is_a?(String)
|
85
|
+
targets = [target_name]
|
86
|
+
elsif target_name.nil?
|
87
|
+
guessed_name = guess_target_name_from_path(base_path)
|
88
|
+
targets = [guessed_name]
|
89
|
+
end
|
90
|
+
else
|
91
|
+
if target_name.is_a?(String) || target_name.nil?
|
92
|
+
targets = [parser.target_for(project, target_name)]
|
93
|
+
elsif target_name.is_a?(Array)
|
94
|
+
targets = target_name.map { |name| parser.target_for(project, name) }
|
95
|
+
end
|
84
96
|
end
|
85
97
|
|
86
98
|
FileCreator.new.create_file_using_template_path(
|
@@ -88,7 +100,19 @@ class FileTemplateDefinition
|
|
88
100
|
generated_filename,
|
89
101
|
group,
|
90
102
|
targets,
|
103
|
+
project,
|
91
104
|
context
|
92
105
|
)
|
93
106
|
end
|
94
|
-
|
107
|
+
|
108
|
+
private def guess_target_name_from_path(path)
|
109
|
+
# SPM standard format
|
110
|
+
parts = path.split(File::SEPARATOR)
|
111
|
+
sources_index = parts.index("Sources")
|
112
|
+
if sources_index && sources_index + 1 < parts.length
|
113
|
+
return parts[sources_index + 1]
|
114
|
+
else
|
115
|
+
return nil
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require_relative 'code_templater'
|
2
2
|
require_relative 'file_creator'
|
3
|
-
require_relative 'pbxproj_parser'
|
4
3
|
|
5
4
|
class GroupTemplateDefinition
|
6
5
|
def initialize(group_template_definition_hash)
|
@@ -22,7 +21,7 @@ class GroupTemplateDefinition
|
|
22
21
|
base_path = merged_variables["base_path"]
|
23
22
|
raise "Missing base_path variable" if base_path.nil?
|
24
23
|
|
25
|
-
base_group = project
|
24
|
+
base_group = XcodeGroupRepresentation.findGroup(base_path, project)
|
26
25
|
raise "Base path \"#{base_path}\" is missing" if base_group.nil?
|
27
26
|
end
|
28
27
|
|
@@ -30,25 +29,13 @@ class GroupTemplateDefinition
|
|
30
29
|
merged_variables = config.variables_for_template_element(template_definition, @name, @variables)
|
31
30
|
|
32
31
|
base_path = merged_variables["base_path"]
|
33
|
-
base_group = project
|
32
|
+
base_group = XcodeGroupRepresentation.findGroup(base_path, project)
|
34
33
|
group_path = CodeTemplater.new.render_string(@path, context)
|
35
34
|
|
36
|
-
|
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
|
35
|
+
group_path_components = group_path.split("/")
|
36
|
+
group = base_group.create_groups_if_needed_for_intermediate_groups(group_path_components)
|
50
37
|
|
51
38
|
file_creator = FileCreator.new
|
52
|
-
file_creator.
|
39
|
+
file_creator.create_empty_directory_for_group(group)
|
53
40
|
end
|
54
|
-
end
|
41
|
+
end
|
data/lib/ccios/pbxproj_parser.rb
CHANGED
@@ -27,10 +27,10 @@ class PBXProjParser
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def target_for(project, target_name)
|
30
|
-
if target_name.blank?
|
30
|
+
if target_name.blank? || target_name.nil?
|
31
31
|
project.targets.find { |t| t.product_type == "com.apple.product-type.application" }
|
32
32
|
else
|
33
33
|
project.targets.find { |t| t.name == target_name }
|
34
34
|
end
|
35
35
|
end
|
36
|
-
end
|
36
|
+
end
|
@@ -59,10 +59,17 @@ class TemplateDefinition
|
|
59
59
|
raise "Error: invalid template name" unless @name.is_a? String
|
60
60
|
|
61
61
|
merged_variables = config.variables_for_template(self)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
62
|
+
project_type = merged_variables["project_type"] || "xcode"
|
63
|
+
case project_type
|
64
|
+
when "xcode"
|
65
|
+
project_path = merged_variables["project"]
|
66
|
+
project = parser.project_for(project_path)
|
67
|
+
raise "Error: Unable to find project \"#{project_path}\"" if project.nil?
|
68
|
+
when "filesystem"
|
69
|
+
project = nil
|
70
|
+
else
|
71
|
+
raise "Invalid project_type given \"#{project_type}\", only \"xcode\" and \"fiilesystem\" are supported"
|
72
|
+
end
|
66
73
|
|
67
74
|
@template_file_source.each do |file_template_name, path|
|
68
75
|
raise "Missing template source file for \"#{file_template_name}\"" unless File.exist?(self.template_source_file(file_template_name))
|
@@ -93,9 +100,16 @@ class TemplateDefinition
|
|
93
100
|
options = agrument_transformed_options(options)
|
94
101
|
|
95
102
|
merged_variables = config.variables_for_template(self)
|
96
|
-
project_path = merged_variables["project"]
|
97
103
|
|
98
|
-
|
104
|
+
project_type = merged_variables["project_type"] || "xcode"
|
105
|
+
case project_type
|
106
|
+
when "xcode"
|
107
|
+
project_path = merged_variables["project"]
|
108
|
+
project = parser.project_for project_path
|
109
|
+
when "filesystem"
|
110
|
+
project = nil
|
111
|
+
|
112
|
+
end
|
99
113
|
|
100
114
|
@generated_elements.each do |element|
|
101
115
|
element.generate(parser, project, options, self, config)
|
@@ -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(
|
27
|
-
|
27
|
+
init(
|
28
|
+
navigationController: UINavigationController,
|
29
|
+
dependencyProvider: ApplicationDependencyProvider
|
30
|
+
) {
|
28
31
|
self.navigationController = navigationController
|
29
32
|
self.dependencyProvider = dependencyProvider
|
30
33
|
}
|
@@ -2,13 +2,17 @@
|
|
2
2
|
func {{lowercased_name}}Presenter(viewContract: {{name}}ViewContract, presenterDelegate: {{name}}PresenterDelegate) -> {{name}}Presenter? {
|
3
3
|
return presenterAssembler
|
4
4
|
.resolver
|
5
|
-
.resolve(
|
5
|
+
.resolve(
|
6
|
+
{{name}}Presenter.self,
|
7
|
+
arguments: viewContract as {{name}}ViewContract,
|
8
|
+
presenterDelegate as {{name}}PresenterDelegate
|
9
|
+
)
|
6
10
|
}
|
7
11
|
{{/generate_delegate}}
|
8
12
|
{{^generate_delegate}}
|
9
13
|
func {{lowercased_name}}Presenter(viewContract: {{name}}ViewContract) -> {{name}}Presenter? {
|
10
14
|
return presenterAssembler
|
11
15
|
.resolver
|
12
|
-
.resolve({{name}}Presenter.self, argument: viewContract)
|
16
|
+
.resolve({{name}}Presenter.self, argument: viewContract as {{name}}ViewContract)
|
13
17
|
}
|
14
18
|
{{/generate_delegate}}
|
@@ -15,6 +15,8 @@ class {{name}}PresenterImplementation: {{name}}Presenter {
|
|
15
15
|
private weak var delegate: {{name}}PresenterDelegate?
|
16
16
|
{{/generate_delegate}}
|
17
17
|
|
18
|
+
// MARK: - Lifecycle
|
19
|
+
|
18
20
|
{{#generate_delegate}}
|
19
21
|
init(viewContract: {{name}}ViewContract, delegate: {{name}}PresenterDelegate) {
|
20
22
|
self.viewContract = viewContract
|
@@ -30,6 +32,7 @@ class {{name}}PresenterImplementation: {{name}}Presenter {
|
|
30
32
|
// MARK: - {{name}}Presenter
|
31
33
|
|
32
34
|
func start() {
|
33
|
-
|
35
|
+
let viewModel = {{name}}ViewModelMapper().map()
|
36
|
+
viewContract?.configure(with: viewModel)
|
34
37
|
}
|
35
38
|
}
|
@@ -11,7 +11,6 @@ parameters:
|
|
11
11
|
variables:
|
12
12
|
project: "*.xcodeproj"
|
13
13
|
base_path: "App"
|
14
|
-
target: ""
|
15
14
|
generated_elements:
|
16
15
|
- name: "ui_view_group"
|
17
16
|
group: "{{ name }}/UI/View"
|
@@ -32,8 +31,13 @@ generated_elements:
|
|
32
31
|
file: "{{ name }}/Presenter/{{ name }}PresenterImplementation.swift"
|
33
32
|
template: "presenter_implementation"
|
34
33
|
variables: {}
|
35
|
-
- name: "
|
36
|
-
|
34
|
+
- name: "view_model"
|
35
|
+
file: "{{ name }}/Model/{{ name }}ViewModel.swift"
|
36
|
+
template: "view_model"
|
37
|
+
variables: {}
|
38
|
+
- name: "view_model_mapper"
|
39
|
+
file: "{{ name }}/Model/Mapper/{{ name }}ViewModelMapper.swift"
|
40
|
+
template: "view_model_mapper"
|
37
41
|
variables: {}
|
38
42
|
code_snippets:
|
39
43
|
- name: DependencyProvider
|
@@ -45,5 +49,7 @@ template_file_source:
|
|
45
49
|
view_contract: "view_contract.mustache"
|
46
50
|
presenter: "presenter.mustache"
|
47
51
|
presenter_implementation: "presenter_implementation.mustache"
|
52
|
+
view_model: "view_model.mustache"
|
53
|
+
view_model_mapper: "view_model_mapper.mustache"
|
48
54
|
dependency_provider: "dependency_provider.mustache"
|
49
55
|
presenter_assembly: "presenter_assembly.mustache"
|
@@ -12,6 +12,8 @@ import UIKit
|
|
12
12
|
class {{name}}ViewController: SharedViewController, {{name}}ViewContract {
|
13
13
|
var presenter: {{name}}Presenter?
|
14
14
|
|
15
|
+
// MARK: - Lifecycle
|
16
|
+
|
15
17
|
override func viewDidLoad() {
|
16
18
|
super.viewDidLoad()
|
17
19
|
presenter?.start()
|
@@ -19,4 +21,6 @@ class {{name}}ViewController: SharedViewController, {{name}}ViewContract {
|
|
19
21
|
|
20
22
|
// MARK: - {{name}}ViewContract
|
21
23
|
|
24
|
+
func configure(with viewModel: {{name}}ViewModel) {
|
25
|
+
}
|
22
26
|
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
//
|
2
|
+
// {{name}}ViewModelMapper.swift
|
3
|
+
// {{project_name}}
|
4
|
+
//
|
5
|
+
// Created by {{full_username}} on {{date}}.
|
6
|
+
//
|
7
|
+
//
|
8
|
+
|
9
|
+
import Foundation
|
10
|
+
|
11
|
+
struct {{name}}ViewModelMapper {
|
12
|
+
|
13
|
+
func map() -> {{name}}ViewModel {
|
14
|
+
{{name}}ViewModel()
|
15
|
+
}
|
16
|
+
}
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require_relative 'pbxproj_parser'
|
2
|
+
|
3
|
+
# This object handles Xcode groups, folder reference and synchronized folder reference
|
4
|
+
class XcodeGroupRepresentation
|
5
|
+
def self.findGroup(path, project)
|
6
|
+
intermediates_groups = path.split("/")
|
7
|
+
|
8
|
+
if project.nil?
|
9
|
+
return self.new nil, nil, intermediates_groups
|
10
|
+
end
|
11
|
+
|
12
|
+
deepest_group = project.main_group
|
13
|
+
additional_path = []
|
14
|
+
|
15
|
+
intermediates_groups.each do |group_name|
|
16
|
+
if deepest_group.is_a?(Xcodeproj::Project::Object::PBXFileSystemSynchronizedRootGroup)
|
17
|
+
additional_path.append(group_name)
|
18
|
+
elsif deepest_group.is_a?(Xcodeproj::Project::Object::PBXGroup)
|
19
|
+
deepest_group = deepest_group.find_subpath(group_name)
|
20
|
+
return nil if deepest_group.nil?
|
21
|
+
else
|
22
|
+
raise "Unsupported element found with name \"#{group_name}\": #{deepest_group}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
self.new project, deepest_group, additional_path
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(project, xcode_group, additional_path = [])
|
29
|
+
if project.nil?
|
30
|
+
throw "Unexpected xcode_group when project is nil, we should be in an filesystem context" unless xcode_group.nil?
|
31
|
+
else
|
32
|
+
throw "Unsupported group type" unless xcode_group.is_a?(Xcodeproj::Project::Object::PBXFileSystemSynchronizedRootGroup) || xcode_group.is_a?(Xcodeproj::Project::Object::PBXGroup)
|
33
|
+
if !additional_path.empty? && !xcode_group.is_a?(Xcodeproj::Project::Object::PBXFileSystemSynchronizedRootGroup)
|
34
|
+
throw "additional_path can only be specified for a synchronized file system group"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
# This represent the xcode project if present, if nil we should be generating files in an Swift package
|
38
|
+
@project = project
|
39
|
+
# This represents the deepest group or folder reference in the project
|
40
|
+
@xcode_deepest_group = xcode_group
|
41
|
+
# This represents the additional filesystem path after `xcode_deepest_group` as an Array of strings. This should be non empty only when deepest group is a synchronized group
|
42
|
+
@additional_path = additional_path
|
43
|
+
end
|
44
|
+
|
45
|
+
def real_path
|
46
|
+
if @xcode_deepest_group.nil?
|
47
|
+
@additional_path.join("/")
|
48
|
+
else
|
49
|
+
Xcodeproj::Project::Object::GroupableHelper.real_path(@xcode_deepest_group) + @additional_path.join("/")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def register_file_to_targets(file_path, targets)
|
55
|
+
if @xcode_deepest_group.nil?
|
56
|
+
return
|
57
|
+
end
|
58
|
+
if @xcode_deepest_group.is_a?(Xcodeproj::Project::Object::PBXGroup)
|
59
|
+
file_ref = @xcode_deepest_group.new_reference(file_path)
|
60
|
+
targets.each do |target|
|
61
|
+
target.add_file_references([file_ref])
|
62
|
+
end
|
63
|
+
else
|
64
|
+
# no file to register, unless exceptions needs to be made
|
65
|
+
# TODO: Handle synchronized groups (no new reference, but use exceptions)
|
66
|
+
targets.each do |taget|
|
67
|
+
puts "Unsupported target mismatch between \"#{file_path}\" and synchronized group #{ @xcode_deepest_group.display_name }" unless taget.file_system_synchronized_groups.index(@xcode_deepest_group) != nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [XcodeGroupRepresentation] the created group or self if the intermediates_groups is empty
|
73
|
+
def create_groups_if_needed_for_intermediate_groups(intermediates_groups)
|
74
|
+
return self if intermediates_groups.empty?
|
75
|
+
|
76
|
+
new_deepest_group = @xcode_deepest_group
|
77
|
+
new_additional_path = @additional_path
|
78
|
+
|
79
|
+
intermediates_groups.each do |group_name|
|
80
|
+
if new_deepest_group.nil? || new_deepest_group.is_a?(Xcodeproj::Project::Object::PBXFileSystemSynchronizedRootGroup)
|
81
|
+
new_additional_path.append(group_name)
|
82
|
+
elsif new_deepest_group.is_a?(Xcodeproj::Project::Object::PBXGroup)
|
83
|
+
existing_child = new_deepest_group.find_subpath(group_name)
|
84
|
+
new_group_path = File.join(new_deepest_group.real_path, group_name)
|
85
|
+
new_deepest_group = existing_child || new_deepest_group.pf_new_group(
|
86
|
+
associate_path_to_group: !new_deepest_group.path.nil?,
|
87
|
+
name: group_name,
|
88
|
+
path: new_group_path
|
89
|
+
)
|
90
|
+
else
|
91
|
+
raise "Unsupported element found for \"#{group_name}\": #{new_deepest_group}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
XcodeGroupRepresentation.new @project, new_deepest_group, new_additional_path
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Private utility method
|
99
|
+
|
100
|
+
class Xcodeproj::Project::Object::PBXGroup
|
101
|
+
def pf_new_group(associate_path_to_group:, name:, path:)
|
102
|
+
new_group(
|
103
|
+
associate_path_to_group ? nil : name,
|
104
|
+
associate_path_to_group ? path : nil
|
105
|
+
)
|
106
|
+
end
|
107
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ccios
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pierre Felgines
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.27'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
40
|
+
version: '1.27'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: mustache
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '13.2'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '13.2'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: minitest
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -93,6 +93,7 @@ files:
|
|
93
93
|
- CHANGELOG.md
|
94
94
|
- Gemfile
|
95
95
|
- Gemfile.lock
|
96
|
+
- MAINTAINER.md
|
96
97
|
- Makefile
|
97
98
|
- README.md
|
98
99
|
- Rakefile
|
@@ -122,11 +123,14 @@ files:
|
|
122
123
|
- lib/ccios/templates/Presenter/template.yml
|
123
124
|
- lib/ccios/templates/Presenter/view_contract.mustache
|
124
125
|
- lib/ccios/templates/Presenter/view_controller.mustache
|
126
|
+
- lib/ccios/templates/Presenter/view_model.mustache
|
127
|
+
- lib/ccios/templates/Presenter/view_model_mapper.mustache
|
125
128
|
- lib/ccios/templates/Repository/repository.mustache
|
126
129
|
- lib/ccios/templates/Repository/repository_assembly.mustache
|
127
130
|
- lib/ccios/templates/Repository/repository_implementation.mustache
|
128
131
|
- lib/ccios/templates/Repository/template.yml
|
129
132
|
- lib/ccios/templates_loader.rb
|
133
|
+
- lib/ccios/xcode_group_representation.rb
|
130
134
|
- templates_library/async/Coordinator/coordinator.mustache
|
131
135
|
- templates_library/async/Coordinator/template.yml
|
132
136
|
- templates_library/async/Presenter/dependency_provider.mustache
|
@@ -156,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
156
160
|
- !ruby/object:Gem::Version
|
157
161
|
version: '0'
|
158
162
|
requirements: []
|
159
|
-
rubygems_version: 3.5.
|
163
|
+
rubygems_version: 3.5.3
|
160
164
|
signing_key:
|
161
165
|
specification_version: 4
|
162
166
|
summary: Clean Code iOS Generator
|