ccios 4.0.2 → 4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f8159d13b805646ece40483ebefb21ff1294579b58e28eaafb3a353274fa554
4
- data.tar.gz: 248f6b498d1b435af918bc1a8675760f426ebf52ffcd1ca7e09f8a8ea85b2b2b
3
+ metadata.gz: 6854ecea6f4dd2478a49675e65dac4f292ddd1e2cae94d526b5903ea507efaf0
4
+ data.tar.gz: eeaa057288fe8c0d0c6d02e0a94453e967e8c1d904a068d5c185f0d49224c252
5
5
  SHA512:
6
- metadata.gz: 8cb1756d184f9291d86f4a4e2a6a4b57d4e43f54dd4e67c9162f209c35333f4bc5657edfb4b6c9e4df361fc6c93d3b4138b7db7a3e1efcdeeb179e4b6d1a0b64
7
- data.tar.gz: 2ba3f77bb27f682a8f2d492a9f52c3a70da99db92e03633afda28b3f64c2f700c12a517731b45d2b3870a5455ef96614d57d447458ed8d074c1bbc0b4eb9fc23
6
+ metadata.gz: 34837239dd73f4e62f167a078a48fb3083b49296c9970032f86ba768128af08b991c5f46adc72b032fbc909d4937e82487fcdea65d0cb6b9eaaa9049c2261580
7
+ data.tar.gz: a480d7df1ee5dc7a9d595ec6fcb4c68ad968ca2b62e9c57065ff7a3e3ad5528f2ffd0e3d76dfe01f6f6ba2cad71fab65ffafc5148b2fbbf202e978b0a65c1f61
@@ -8,11 +8,11 @@ jobs:
8
8
  runs-on: ubuntu-latest
9
9
 
10
10
  steps:
11
- - uses: actions/checkout@v1
12
- - name: Set up Ruby 2.6
13
- uses: actions/setup-ruby@v1
11
+ - uses: actions/checkout@v4
12
+ - name: Set up Ruby 3.2
13
+ uses: ruby/setup-ruby@v1
14
14
  with:
15
- ruby-version: 2.6.x
15
+ bundler-cache: true
16
16
  - name: Build and test with Rake
17
17
  run: |
18
18
  gem install bundler
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.2
data/CHANGELOG.md CHANGED
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [4.1.0]
8
+
9
+ ### Added
10
+ - Allow user to overload templates with local version thanks to the new config parameter in `.ccios.yml`
11
+
7
12
  ## [4.0.2]
8
13
 
9
14
  ### Fixed
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ccios (4.0.2)
4
+ ccios (4.1.0)
5
5
  activesupport (> 4)
6
6
  mustache (~> 1.0)
7
7
  xcodeproj (~> 1.4)
@@ -9,32 +9,33 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- CFPropertyList (3.0.3)
13
- activesupport (6.1.3)
12
+ CFPropertyList (3.0.6)
13
+ rexml
14
+ activesupport (7.0.8)
14
15
  concurrent-ruby (~> 1.0, >= 1.0.2)
15
16
  i18n (>= 1.6, < 2)
16
17
  minitest (>= 5.1)
17
18
  tzinfo (~> 2.0)
18
- zeitwerk (~> 2.3)
19
19
  atomos (0.1.3)
20
- claide (1.0.3)
20
+ claide (1.1.0)
21
21
  colored2 (3.1.2)
22
- concurrent-ruby (1.1.8)
23
- i18n (1.8.9)
22
+ concurrent-ruby (1.2.2)
23
+ i18n (1.14.1)
24
24
  concurrent-ruby (~> 1.0)
25
- minitest (5.14.2)
25
+ minitest (5.20.0)
26
26
  mustache (1.1.1)
27
27
  nanaimo (0.3.0)
28
28
  rake (12.3.3)
29
- tzinfo (2.0.4)
29
+ rexml (3.2.6)
30
+ tzinfo (2.0.6)
30
31
  concurrent-ruby (~> 1.0)
31
- xcodeproj (1.19.0)
32
+ xcodeproj (1.23.0)
32
33
  CFPropertyList (>= 2.3.3, < 4.0)
33
34
  atomos (~> 0.1.3)
34
35
  claide (>= 1.0.2, < 2.0)
35
36
  colored2 (~> 3.1)
36
37
  nanaimo (~> 0.3.0)
37
- zeitwerk (2.4.2)
38
+ rexml (~> 3.2.4)
38
39
 
39
40
  PLATFORMS
40
41
  ruby
@@ -45,4 +46,4 @@ DEPENDENCIES
45
46
  rake (~> 12.3)
46
47
 
47
48
  BUNDLED WITH
48
- 1.17.3
49
+ 2.4.10
data/README.md CHANGED
@@ -154,8 +154,14 @@ data:
154
154
  target: MyProjectData # optional
155
155
  repository:
156
156
  group: MyProjectData/Sources/Repositories
157
-
158
157
  ```
159
158
 
160
159
  *Note*: The path of the new files will be infered from the path of the group. It works with *Group with folder* and *Group without folder* in Xcode.
161
160
 
161
+ And lastly you may want to use your own templates, by adding this parameter to the file:
162
+ ```
163
+ templates:
164
+ path: Path/To/Users/Templates
165
+ ```
166
+
167
+
data/ccios.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'ccios'
3
- s.version = '4.0.2'
3
+ s.version = '4.1.0'
4
4
  s.executables << 'ccios'
5
5
  s.date = '2016-08-03'
6
6
  s.summary = "Clean Code iOS Generator"
@@ -2,14 +2,15 @@ require 'mustache'
2
2
  require 'active_support/core_ext/string'
3
3
 
4
4
  class CodeTemplater
5
- def initialize(options = {})
5
+ def initialize(options = {}, templates_path)
6
6
  @options = options
7
+ @templates_path = templates_path
7
8
  end
8
9
 
9
10
  def content_for_suffix(prefix, suffix)
10
11
  template_name = suffix.underscore
11
12
  options = @options.merge({name: prefix, lowercased_name: prefix.camelize(:lower)})
12
- template_file = File.join(File.dirname(__FILE__), "templates/#{template_name}.mustache")
13
+ template_file = File.join(@templates_path, "#{template_name}.mustache")
13
14
  Mustache.render(File.read(template_file), options)
14
15
  end
15
16
  end
data/lib/ccios/config.rb CHANGED
@@ -2,14 +2,14 @@ require 'yaml'
2
2
 
3
3
  class Config
4
4
 
5
- attr_reader :app, :core, :data
5
+ attr_reader :app, :core, :data, :templates
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
10
  self.new config, source_path
11
11
  else
12
- puts "File #{source_path} does not exists. Using default config."
12
+ puts "File #{source_path} does not exist. Using default config."
13
13
  self.default
14
14
  end
15
15
  end
@@ -30,7 +30,8 @@ class Config
30
30
  "data" => {
31
31
  "project" => project,
32
32
  "repository" => {"group" => "Classes/Data"}
33
- }
33
+ },
34
+ "templates" => self.default_templates_hash
34
35
  }
35
36
  end
36
37
 
@@ -38,12 +39,21 @@ class Config
38
39
  self.new default_config_hash
39
40
  end
40
41
 
42
+ def self.default_templates_hash
43
+ { "path" => File.join(File.dirname(__FILE__), "templates") }
44
+ end
45
+
41
46
  def initialize(config_hash, source_path = nil)
42
47
  @source_path = source_path
43
48
  validate config_hash
44
49
  @app = AppConfig.new config_hash["app"]
45
50
  @core = CoreConfig.new config_hash["core"]
46
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"]
56
+ end
47
57
  end
48
58
 
49
59
  def validate(hash)
@@ -107,10 +117,17 @@ class DataConfig
107
117
  end
108
118
 
109
119
  class ObjectConfig
110
-
111
120
  attr_reader :group
112
121
 
113
122
  def initialize(hash)
114
123
  @group = hash["group"]
115
124
  end
116
125
  end
126
+
127
+ class TemplatesConfig
128
+ attr_reader :path
129
+
130
+ def initialize(hash)
131
+ @path = hash["path"]
132
+ end
133
+ end
@@ -10,7 +10,7 @@ class CoordinatorGenerator
10
10
 
11
11
  def generate(coordinator_name, options = {})
12
12
  coordinator_group = @parser.coordinator_group
13
- file_creator = FileCreator.new(options)
13
+ file_creator = FileCreator.new(options, @config)
14
14
  target = @parser.app_target
15
15
  coordinator_name = coordinator_name.gsub("Coordinator", "")
16
16
  file_creator.create_file(coordinator_name, 'Coordinator', coordinator_group, target)
@@ -24,8 +24,9 @@ class FileCreator
24
24
  FileCreator.logger
25
25
  end
26
26
 
27
- def initialize(options = {})
27
+ def initialize(options = {}, config)
28
28
  @options = options
29
+ @config = config
29
30
  end
30
31
 
31
32
  def templater_options(target)
@@ -50,7 +51,7 @@ class FileCreator
50
51
  file = File.new(file_path, 'w')
51
52
 
52
53
  templater_options = templater_options(target)
53
- code_templater = CodeTemplater.new(templater_options)
54
+ code_templater = CodeTemplater.new(templater_options, @config.templates.path)
54
55
  file_content = code_templater.content_for_suffix(prefix, suffix)
55
56
  file.puts(file_content)
56
57
 
@@ -70,7 +71,7 @@ class FileCreator
70
71
  def print_file_content(prefix, suffix)
71
72
  file_name = suffix + '.swift'
72
73
 
73
- code_templater = CodeTemplater.new(@options)
74
+ code_templater = CodeTemplater.new(@options, @config.templates.path)
74
75
  template = code_templater.content_for_suffix(prefix, suffix)
75
76
 
76
77
  logger.info "Add this snippet to #{file_name}"
@@ -23,7 +23,7 @@ class InteractorGenerator
23
23
  path: new_group_path
24
24
  )
25
25
 
26
- file_creator = FileCreator.new(options)
26
+ file_creator = FileCreator.new(options, @config)
27
27
  target = @parser.core_target
28
28
  file_creator.create_file(interactor_name, 'Interactor', new_group, target)
29
29
  file_creator.create_file(interactor_name, 'InteractorImplementation', new_group, target)
@@ -56,7 +56,7 @@ class PresenterGenerator
56
56
  path: model_group_path
57
57
  )
58
58
 
59
- file_creator = FileCreator.new(options)
59
+ file_creator = FileCreator.new(options, @config)
60
60
  target = @parser.app_target
61
61
  file_creator.create_file(presenter_name, 'ViewContract', ui_group, target)
62
62
  file_creator.create_file(presenter_name, 'ViewController', view_controller_group, target)
@@ -31,11 +31,11 @@ class RepositoryGenerator
31
31
  path: data_new_group_path
32
32
  )
33
33
 
34
- file_creator = FileCreator.new(options)
34
+ file_creator = FileCreator.new(options, @config)
35
35
  core_target = @parser.core_target
36
36
  file_creator.create_file(repository_name, 'Repository', core_data_new_group, core_target)
37
37
 
38
- file_creator = FileCreator.new(options)
38
+ file_creator = FileCreator.new(options, @config)
39
39
  data_target = @parser.data_target
40
40
  file_creator.create_file(repository_name, 'RepositoryImplementation', data_new_group, data_target)
41
41
 
@@ -5,7 +5,6 @@
5
5
  // Created by {{full_username}} on {{date}}.
6
6
  //
7
7
  //
8
- //
9
8
 
10
9
  import Foundation
11
10
  import Core
data/lib/ccios.rb CHANGED
@@ -14,20 +14,20 @@ OptionParser.new do |opts|
14
14
  opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
15
15
  options[:verbose] = v
16
16
  end
17
- opts.on("-pName", "--presenter=Name", "Generate NamePresenter, NamePresenterImplementation, NameViewContract and NameViewController") do |v|
18
- options[:presenter] = v
17
+ opts.on("-pName", "--presenter=Name", "Generate NamePresenter, NamePresenterImplementation, NameViewContract and NameViewController") do |name|
18
+ options[:presenter] = name
19
19
  end
20
- opts.on("-cName", "--coordinator=Name", "Generate NameCoordinator") do |v|
21
- options[:coordinator] = v
20
+ opts.on("-cName", "--coordinator=Name", "Generate NameCoordinator") do |name|
21
+ options[:coordinator] = name
22
22
  end
23
- opts.on("-iName", "--interactor=Name", "Generate NameInteractor and NameInteractorImplementation") do |v|
24
- options[:interactor] = v
23
+ opts.on("-iName", "--interactor=Name", "Generate NameInteractor and NameInteractorImplementation") do |name|
24
+ options[:interactor] = name
25
25
  end
26
- opts.on("-rName", "--repository=Name", "Generate NameRepository and NameRepositoryImplementation") do |v|
27
- options[:repository] = v
26
+ opts.on("-rName", "--repository=Name", "Generate NameRepository and NameRepositoryImplementation") do |name|
27
+ options[:repository] = name
28
28
  end
29
- opts.on("-d", "--delegate", "Add delegate for curent generation") do |v|
30
- options[:generate_delegate] = v
29
+ opts.on("-d", "--delegate", "Add delegate for curent generation") do |add_delegate|
30
+ options[:generate_delegate] = add_delegate
31
31
  end
32
32
  opts.on("-h", "--help", "Print this help") do
33
33
  puts opts
@@ -0,0 +1,41 @@
1
+ //
2
+ // {{name}}Coordinator.swift
3
+ // {{project_name}}
4
+ //
5
+ // Created by {{full_username}} on {{date}}.
6
+ //
7
+ //
8
+
9
+ import Foundation
10
+ import ADCoordinator
11
+
12
+ {{#generate_delegate}}
13
+ @MainActor
14
+ protocol {{name}}CoordinatorDelegate: AnyObject {
15
+
16
+ }
17
+
18
+ {{/generate_delegate}}
19
+ @MainActor
20
+ class {{name}}Coordinator: Coordinator {
21
+
22
+ {{#generate_delegate}}
23
+ weak var delegate: {{name}}CoordinatorDelegate?
24
+ {{/generate_delegate}}
25
+ private let dependencyProvider: ApplicationDependencyProvider
26
+ private unowned var navigationController: UINavigationController
27
+
28
+ nonisolated init(navigationController: UINavigationController,
29
+ dependencyProvider: ApplicationDependencyProvider) {
30
+ self.navigationController = navigationController
31
+ self.dependencyProvider = dependencyProvider
32
+ }
33
+
34
+ // MARK: - Public
35
+
36
+ func start() {
37
+ let viewController = UIViewController()
38
+ navigationController.pushViewController(viewController, animated: false)
39
+ bindToLifecycle(of: viewController)
40
+ }
41
+ }
@@ -0,0 +1,14 @@
1
+ {{#generate_delegate}}
2
+ func {{lowercased_name}}Presenter(viewContract: {{name}}ViewContract, presenterDelegate: {{name}}PresenterDelegate) -> {{name}}Presenter? {
3
+ return presenterAssembler
4
+ .resolver
5
+ .resolve({{name}}Presenter.self, arguments: viewContract, presenterDelegate)
6
+ }
7
+ {{/generate_delegate}}
8
+ {{^generate_delegate}}
9
+ func {{lowercased_name}}Presenter(viewContract: {{name}}ViewContract) -> {{name}}Presenter? {
10
+ return presenterAssembler
11
+ .resolver
12
+ .resolve({{name}}Presenter.self, argument: viewContract)
13
+ }
14
+ {{/generate_delegate}}
@@ -0,0 +1,13 @@
1
+ //
2
+ // {{name}}Interactor.swift
3
+ // {{project_name}}
4
+ //
5
+ // Created by {{full_username}} on {{date}}.
6
+ //
7
+ //
8
+
9
+ import Foundation
10
+
11
+ public protocol {{name}}Interactor {
12
+ func execute() async throws
13
+ }
@@ -0,0 +1,5 @@
1
+ container.register({{name}}Interactor.self) { _ in
2
+ {{name}}InteractorImplementation(
3
+
4
+ )
5
+ }
@@ -0,0 +1,22 @@
1
+ //
2
+ // {{name}}InteractorImplementation.swift
3
+ // {{project_name}}
4
+ //
5
+ // Created by {{full_username}} on {{date}}.
6
+ //
7
+ //
8
+
9
+ import Foundation
10
+
11
+ public class {{name}}InteractorImplementation: {{name}}Interactor {
12
+
13
+ public init() {
14
+
15
+ }
16
+
17
+ // MARK: - {{name}}Interactor
18
+
19
+ public func execute() async throws {
20
+
21
+ }
22
+ }
@@ -0,0 +1,21 @@
1
+ //
2
+ // {{name}}Presenter.swift
3
+ // {{project_name}}
4
+ //
5
+ // Created by {{full_username}} on {{date}}.
6
+ //
7
+ //
8
+
9
+ import Foundation
10
+
11
+ @MainActor
12
+ protocol {{name}}Presenter {
13
+ func start()
14
+ }
15
+ {{#generate_delegate}}
16
+
17
+ @MainActor
18
+ protocol {{name}}PresenterDelegate: AnyObject {
19
+
20
+ }
21
+ {{/generate_delegate}}
@@ -0,0 +1,15 @@
1
+ {{#generate_delegate}}
2
+ container.register({{name}}Presenter.self) { _, viewContract, delegate in
3
+ {{name}}PresenterImplementation(
4
+ viewContract: viewContract,
5
+ delegate: delegate
6
+ )
7
+ }
8
+ {{/generate_delegate}}
9
+ {{^generate_delegate}}
10
+ container.register({{name}}Presenter.self) { _, viewContract in
11
+ {{name}}PresenterImplementation(
12
+ viewContract: viewContract
13
+ )
14
+ }
15
+ {{/generate_delegate}}
@@ -0,0 +1,35 @@
1
+ //
2
+ // {{name}}PresenterImplementation.swift
3
+ // {{project_name}}
4
+ //
5
+ // Created by {{full_username}} on {{date}}.
6
+ //
7
+ //
8
+
9
+ import Foundation
10
+
11
+ class {{name}}PresenterImplementation: {{name}}Presenter {
12
+
13
+ private weak var viewContract: {{name}}ViewContract?
14
+ {{#generate_delegate}}
15
+ private weak var delegate: {{name}}PresenterDelegate?
16
+ {{/generate_delegate}}
17
+
18
+ {{#generate_delegate}}
19
+ nonisolated init(viewContract: {{name}}ViewContract, delegate: {{name}}PresenterDelegate) {
20
+ self.viewContract = viewContract
21
+ self.delegate = delegate
22
+ }
23
+ {{/generate_delegate}}
24
+ {{^generate_delegate}}
25
+ nonisolated init(viewContract: {{name}}ViewContract) {
26
+ self.viewContract = viewContract
27
+ }
28
+ {{/generate_delegate}}
29
+
30
+ // MARK: - {{name}}Presenter
31
+
32
+ func start() {
33
+
34
+ }
35
+ }
@@ -0,0 +1,13 @@
1
+ //
2
+ // {{name}}Repository.swift
3
+ // {{project_name}}
4
+ //
5
+ // Created by {{full_username}} on {{date}}.
6
+ //
7
+ //
8
+
9
+ import Foundation
10
+
11
+ public protocol {{name}}Repository {
12
+
13
+ }
@@ -0,0 +1,6 @@
1
+ container.register({{name}}Repository.self) { _ in
2
+ {{name}}RepositoryImplementation(
3
+
4
+ )
5
+ }
6
+ .inObjectScope(.container)
@@ -0,0 +1,20 @@
1
+ //
2
+ // {{name}}RepositoryImplementation.swift
3
+ // {{project_name}}
4
+ //
5
+ // Created by {{full_username}} on {{date}}.
6
+ //
7
+ //
8
+
9
+ import Foundation
10
+ import Core
11
+
12
+ public class {{name}}RepositoryImplementation: {{name}}Repository {
13
+
14
+ public init() {
15
+
16
+ }
17
+
18
+ // MARK: - {{name}}Repository
19
+
20
+ }
@@ -0,0 +1,14 @@
1
+ //
2
+ // {{name}}ViewContract.swift
3
+ // {{project_name}}
4
+ //
5
+ // Created by {{full_username}} on {{date}}.
6
+ //
7
+ //
8
+
9
+ import Foundation
10
+
11
+ @MainActor
12
+ protocol {{name}}ViewContract: AnyObject {
13
+
14
+ }
@@ -0,0 +1,23 @@
1
+ //
2
+ // {{name}}ViewController.swift
3
+ // {{project_name}}
4
+ //
5
+ // Created by {{full_username}} on {{date}}.
6
+ //
7
+ //
8
+
9
+ import Foundation
10
+ import UIKit
11
+
12
+ @MainActor
13
+ class {{name}}ViewController: SharedViewController, {{name}}ViewContract {
14
+ var presenter: {{name}}Presenter?
15
+
16
+ override func viewDidLoad() {
17
+ super.viewDidLoad()
18
+ presenter?.start()
19
+ }
20
+
21
+ // MARK: - {{name}}ViewContract
22
+
23
+ }
@@ -0,0 +1 @@
1
+ Default templates are in <root>/lib/ccios/templates
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ccios
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.2
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pierre Felgines
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2016-08-03 00:00:00.000000000 Z
@@ -89,6 +89,7 @@ extra_rdoc_files: []
89
89
  files:
90
90
  - ".github/workflows/ruby.yml"
91
91
  - ".gitignore"
92
+ - ".ruby-version"
92
93
  - CHANGELOG.md
93
94
  - Gemfile
94
95
  - Gemfile.lock
@@ -119,11 +120,25 @@ files:
119
120
  - lib/ccios/templates/repository_implementation.mustache
120
121
  - lib/ccios/templates/view_contract.mustache
121
122
  - lib/ccios/templates/view_controller.mustache
123
+ - templates_library/async/coordinator.mustache
124
+ - templates_library/async/dependency_provider.mustache
125
+ - templates_library/async/interactor.mustache
126
+ - templates_library/async/interactor_assembly.mustache
127
+ - templates_library/async/interactor_implementation.mustache
128
+ - templates_library/async/presenter.mustache
129
+ - templates_library/async/presenter_assembly.mustache
130
+ - templates_library/async/presenter_implementation.mustache
131
+ - templates_library/async/repository.mustache
132
+ - templates_library/async/repository_assembly.mustache
133
+ - templates_library/async/repository_implementation.mustache
134
+ - templates_library/async/view_contract.mustache
135
+ - templates_library/async/view_controller.mustache
136
+ - templates_library/default/README.md
122
137
  homepage: http://rubygems.org/gems/hola
123
138
  licenses:
124
139
  - MIT
125
140
  metadata: {}
126
- post_install_message:
141
+ post_install_message:
127
142
  rdoc_options: []
128
143
  require_paths:
129
144
  - lib
@@ -138,8 +153,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
153
  - !ruby/object:Gem::Version
139
154
  version: '0'
140
155
  requirements: []
141
- rubygems_version: 3.0.3
142
- signing_key:
156
+ rubygems_version: 3.4.10
157
+ signing_key:
143
158
  specification_version: 4
144
159
  summary: Clean Code iOS Generator
145
160
  test_files: []