├── .codeclimate.yml
├── .gitignore
├── .rspec
├── .travis.yml
├── CHANGELOG.md
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── VISION.md
├── bin
├── console
├── generamba
└── setup
├── docs
└── 2.x
│ └── roadmap.md
├── generamba.gemspec
├── lib
├── generamba.rb
└── generamba
│ ├── cli
│ ├── cli.rb
│ ├── gen_command.rb
│ ├── setup_command.rb
│ ├── setup_username_command.rb
│ ├── template
│ │ ├── template_create_command.rb
│ │ ├── template_group.rb
│ │ ├── template_install_command.rb
│ │ ├── template_list_command.rb
│ │ └── template_search_command.rb
│ ├── thor_extension.rb
│ └── version_command.rb
│ ├── code_generation
│ ├── Rambafile.liquid
│ ├── code_module.rb
│ ├── content_generator.rb
│ ├── module_template.rb
│ └── rambafile_generator.rb
│ ├── configuration
│ └── user_preferences.rb
│ ├── constants
│ ├── constants.rb
│ ├── rambafile_constants.rb
│ ├── rambaspec_constants.rb
│ └── user_preferences_constants.rb
│ ├── helpers
│ ├── dependency_checker.rb
│ ├── gen_command_table_parameters_formatter.rb
│ ├── module_info_generator.rb
│ ├── module_validator.rb
│ ├── print_table.rb
│ ├── rambafile_validator.rb
│ ├── template_helper.rb
│ └── xcodeproj_helper.rb
│ ├── module_generator.rb
│ ├── template
│ ├── creator
│ │ ├── new_template
│ │ │ ├── Code
│ │ │ │ └── Service
│ │ │ │ │ ├── service.h.liquid
│ │ │ │ │ └── service.m.liquid
│ │ │ ├── Tests
│ │ │ │ └── Service
│ │ │ │ │ └── service_tests.m.liquid
│ │ │ └── template.rambaspec.liquid
│ │ └── template_creator.rb
│ ├── helpers
│ │ ├── catalog_downloader.rb
│ │ ├── catalog_template_list_helper.rb
│ │ ├── catalog_template_search_helper.rb
│ │ ├── catalog_terminator.rb
│ │ └── rambaspec_validator.rb
│ ├── installer
│ │ ├── abstract_installer.rb
│ │ ├── catalog_installer.rb
│ │ ├── local_installer.rb
│ │ ├── remote_installer.rb
│ │ └── template_installer_factory.rb
│ └── processor
│ │ ├── template_declaration.rb
│ │ └── template_processor.rb
│ ├── tools
│ └── string-colorize.rb
│ └── version.rb
└── spec
├── catalog_downloader_spec.rb
├── catalog_installer_spec.rb
├── catalog_template_list_helper_spec.rb
├── catalog_template_search_helper_spec.rb
├── dependency_checker_spec.rb
├── gen_command_table_parameters_formatter_spec.rb
├── generamba_spec.rb
├── spec_helper.rb
├── template_installer_factory_spec.rb
├── template_processor_spec.rb
└── xcodeproj_helper_spec.rb
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | engines:
2 | rubocop:
3 | enabled: true
4 |
5 | ratings:
6 | paths:
7 | - "**.rb"
8 |
9 | exclude_paths:
10 | - spec/**/*
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/*
2 | .rakeTasks
3 | encodings.xml
4 | Gemfile.lock
5 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --format documentation
2 | --color
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | osx_image: xcode7.3
3 |
4 | cache:
5 | bundler: true
6 |
7 | bundler_args: --jobs 3 --retry 3
8 |
9 | rvm:
10 | - 2.2.1
11 | - 2.3.1
12 |
13 | before_install:
14 | - gem update --system --no-document
15 | - gem install bundler -v 1.17.3 --no-document
16 |
17 | script: bundle exec rake
18 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## [1.5.0](https://github.com/rambler-digital-solutions/Generamba/tree/1.5.0) (2019-04-29)
4 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/1.4.1...1.5.0)
5 |
6 | **Merged pull requests:**
7 |
8 | * Resolve Cocoapods Dependency hell [\#230](https://github.com/strongself/Generamba/pull/230)
9 | * Update xcodeproj & cocoapods-core dependencies [\#222](https://github.com/strongself/Generamba/pull/222)
10 | * Bump gems versions [\#201](https://github.com/strongself/Generamba/pull/201)
11 | * Remove the author-specific information from Rambafile [\#1](https://github.com/strongself/Generamba/issues/1)
12 | * Grammar fixes [\#1](https://github.com/strongself/Generamba/pull/198)
13 |
14 | ## [1.4.1](https://github.com/rambler-digital-solutions/Generamba/tree/1.4.1) (2017-09-04)
15 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/1.4.0...1.4.1)
16 |
17 | **Merged pull requests:**
18 |
19 | * Do not clear tests group if **test\_group\_path** is the same as **project\_group\_path** [\#193](https://github.com/rambler-digital-solutions/Generamba/pull/193) ([RamTararam](https://github.com/RamTararam))
20 |
21 | ## [1.2.2](https://github.com/rambler-digital-solutions/Generamba/tree/1.2.2) (2016-09-27)
22 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/1.2.1...1.2.2)
23 |
24 | ## [1.2.1](https://github.com/rambler-digital-solutions/Generamba/tree/1.2.1) (2016-09-26)
25 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/1.2.0...1.2.1)
26 |
27 | **Fixed bugs:**
28 |
29 | - Crashes for multiple project targets [\#150](https://github.com/rambler-digital-solutions/Generamba/issues/150)
30 |
31 | **Closed issues:**
32 |
33 | - Can I create a template to generate swift-like structure objects for ObjC? [\#157](https://github.com/rambler-digital-solutions/Generamba/issues/157)
34 | - Error generate module with option :exclusive=\>true in Podfile [\#154](https://github.com/rambler-digital-solutions/Generamba/issues/154)
35 | - Module Generation Settings with project\_targets [\#151](https://github.com/rambler-digital-solutions/Generamba/issues/151)
36 |
37 | ## [1.2.0](https://github.com/rambler-digital-solutions/Generamba/tree/1.2.0) (2016-09-05)
38 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/1.1.0...1.2.0)
39 |
40 | **Fixed bugs:**
41 |
42 | - Файлы в корне модуля [\#147](https://github.com/rambler-digital-solutions/Generamba/issues/147)
43 |
44 | **Merged pull requests:**
45 |
46 | - Bug fixes and refactoring [\#148](https://github.com/rambler-digital-solutions/Generamba/pull/148) ([Beniamiiin](https://github.com/Beniamiiin))
47 |
48 | ## [1.1.0](https://github.com/rambler-digital-solutions/Generamba/tree/1.1.0) (2016-09-05)
49 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/1.0.0...1.1.0)
50 |
51 | **Implemented enhancements:**
52 |
53 | - Refactoring rambafile and module validation [\#144](https://github.com/rambler-digital-solutions/Generamba/issues/144)
54 | - Update gen command parameters table [\#142](https://github.com/rambler-digital-solutions/Generamba/issues/142)
55 | - If statement in .rambaspec [\#128](https://github.com/rambler-digital-solutions/Generamba/issues/128)
56 | - Ask user, he want create all modules by one path? [\#126](https://github.com/rambler-digital-solutions/Generamba/issues/126)
57 |
58 | **Fixed bugs:**
59 |
60 | - Generates files with a wrongs paths. [\#138](https://github.com/rambler-digital-solutions/Generamba/issues/138)
61 | - Install templates from git repo is broken? [\#135](https://github.com/rambler-digital-solutions/Generamba/issues/135)
62 | - Error creating the Xcode group path to new modules [\#129](https://github.com/rambler-digital-solutions/Generamba/issues/129)
63 | - If statement in .rambaspec [\#128](https://github.com/rambler-digital-solutions/Generamba/issues/128)
64 |
65 | **Closed issues:**
66 |
67 | - Error: `parse': \(Rambafile\): block sequence entries are not allowed [\#127](https://github.com/rambler-digital-solutions/Generamba/issues/127)
68 |
69 | **Merged pull requests:**
70 |
71 | - \[RESOLVED\] Added question in setup command \#126 [\#146](https://github.com/rambler-digital-solutions/Generamba/pull/146) ([Beniamiiin](https://github.com/Beniamiiin))
72 | - \[RESOLVED\] Updated logic of rambafile and module validation \#144 [\#145](https://github.com/rambler-digital-solutions/Generamba/pull/145) ([Beniamiiin](https://github.com/Beniamiiin))
73 | - \[RESOLVED\] Updated gen command parameters table \#142 [\#143](https://github.com/rambler-digital-solutions/Generamba/pull/143) ([Beniamiiin](https://github.com/Beniamiiin))
74 | - \[RESOLVED\] Added ability use custom parameters in rambaspec \#128 [\#141](https://github.com/rambler-digital-solutions/Generamba/pull/141) ([Beniamiiin](https://github.com/Beniamiiin))
75 | - \[FIXED\] Fixed bug \#138 [\#140](https://github.com/rambler-digital-solutions/Generamba/pull/140) ([Beniamiiin](https://github.com/Beniamiiin))
76 | - Added product\_module\_name to code\_module [\#139](https://github.com/rambler-digital-solutions/Generamba/pull/139) ([mogol](https://github.com/mogol))
77 | - A little refactoring [\#137](https://github.com/rambler-digital-solutions/Generamba/pull/137) ([Beniamiiin](https://github.com/Beniamiiin))
78 | - Support Ruby 2.3.1 [\#134](https://github.com/rambler-digital-solutions/Generamba/pull/134) ([ivaravko](https://github.com/ivaravko))
79 | - Helpers code style [\#133](https://github.com/rambler-digital-solutions/Generamba/pull/133) ([ivaravko](https://github.com/ivaravko))
80 | - Adds Code Climate config [\#132](https://github.com/rambler-digital-solutions/Generamba/pull/132) ([ivaravko](https://github.com/ivaravko))
81 |
82 | ## [1.0.0](https://github.com/rambler-digital-solutions/Generamba/tree/1.0.0) (2016-07-23)
83 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/0.7.8...1.0.0)
84 |
85 | **Implemented enhancements:**
86 |
87 | - Add more info to `generamba version` command [\#122](https://github.com/rambler-digital-solutions/Generamba/issues/122)
88 | - Empty group in Xcode structure [\#118](https://github.com/rambler-digital-solutions/Generamba/issues/118)
89 | - Gem dependency of cocoapods-core-0.39.0 [\#114](https://github.com/rambler-digital-solutions/Generamba/issues/114)
90 | - Remove adding module name in module\_group\_path if it set from cli [\#98](https://github.com/rambler-digital-solutions/Generamba/issues/98)
91 | - Check for missing Carthage dependencies [\#83](https://github.com/rambler-digital-solutions/Generamba/issues/83)
92 | - Automatic tests generation based on protocols and class interfaces [\#71](https://github.com/rambler-digital-solutions/Generamba/issues/71)
93 | - Track all modules created by Generamba [\#70](https://github.com/rambler-digital-solutions/Generamba/issues/70)
94 |
95 | **Fixed bugs:**
96 |
97 | - Can't add file with type . Only 'source' and 'resource' are acceptable [\#116](https://github.com/rambler-digital-solutions/Generamba/issues/116)
98 | - If option --module-group-path starts with '/' Generamba add folder with empty name in root folder [\#99](https://github.com/rambler-digital-solutions/Generamba/issues/99)
99 |
100 | ## [0.7.8](https://github.com/rambler-digital-solutions/Generamba/tree/0.7.8) (2016-05-16)
101 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/0.7.7...0.7.8)
102 |
103 | ## [0.7.7](https://github.com/rambler-digital-solutions/Generamba/tree/0.7.7) (2016-05-10)
104 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/0.7.6...0.7.7)
105 |
106 | **Implemented enhancements:**
107 |
108 | - Project target name in module\_info [\#110](https://github.com/rambler-digital-solutions/Generamba/issues/110)
109 | - Give a user more information about templates during `generamba setup` [\#86](https://github.com/rambler-digital-solutions/Generamba/issues/86)
110 |
111 | ## [0.7.6](https://github.com/rambler-digital-solutions/Generamba/tree/0.7.6) (2016-04-30)
112 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/0.7.5...0.7.6)
113 |
114 | **Fixed bugs:**
115 |
116 | - Failed adding files to project [\#96](https://github.com/rambler-digital-solutions/Generamba/issues/96)
117 |
118 | ## [0.7.5](https://github.com/rambler-digital-solutions/Generamba/tree/0.7.5) (2016-04-24)
119 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/0.7.4...0.7.5)
120 |
121 | **Implemented enhancements:**
122 |
123 | - Get templates from git by specific a branch [\#104](https://github.com/rambler-digital-solutions/Generamba/issues/104)
124 |
125 | **Fixed bugs:**
126 |
127 | - Non human exception when wrong template name or catalog [\#77](https://github.com/rambler-digital-solutions/Generamba/issues/77)
128 |
129 | **Closed issues:**
130 |
131 | - Module Name in .rambaspec support [\#102](https://github.com/rambler-digital-solutions/Generamba/issues/102)
132 | - Generate with project and tests targets in command line [\#97](https://github.com/rambler-digital-solutions/Generamba/issues/97)
133 | - Easy setup template path to local templates in Rambafile [\#94](https://github.com/rambler-digital-solutions/Generamba/issues/94)
134 |
135 | ## [0.7.4](https://github.com/rambler-digital-solutions/Generamba/tree/0.7.4) (2016-02-21)
136 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/0.7.3...0.7.4)
137 |
138 | **Implemented enhancements:**
139 |
140 | - Asks the user if he needed tests in `generamba setup` command [\#85](https://github.com/rambler-digital-solutions/Generamba/issues/85)
141 | - Improve the visualization of commands with parameters [\#69](https://github.com/rambler-digital-solutions/Generamba/issues/69)
142 | - Can we introduce something similar to view partials in rails \(for duplicated parts of views\) [\#62](https://github.com/rambler-digital-solutions/Generamba/issues/62)
143 |
144 | **Fixed bugs:**
145 |
146 | - Add resources\(xib, storyboard and etc\) in project bundle resources. [\#84](https://github.com/rambler-digital-solutions/Generamba/issues/84)
147 |
148 | **Closed issues:**
149 |
150 | - Get "Liquid error: This liquid context does not allow includes." on all files in just generated module [\#93](https://github.com/rambler-digital-solutions/Generamba/issues/93)
151 |
152 | ## [0.7.3](https://github.com/rambler-digital-solutions/Generamba/tree/0.7.3) (2016-01-24)
153 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/0.7.2...0.7.3)
154 |
155 | **Implemented enhancements:**
156 |
157 | - Enhance `generamba template search` to search templates in custom catalogs [\#75](https://github.com/rambler-digital-solutions/Generamba/issues/75)
158 | - Enhance `generamba template list` to browse custom catalogs [\#74](https://github.com/rambler-digital-solutions/Generamba/issues/74)
159 |
160 | **Closed issues:**
161 |
162 | - Can we use constants from rambafile in templates? [\#81](https://github.com/rambler-digital-solutions/Generamba/issues/81)
163 |
164 | ## [0.7.2](https://github.com/rambler-digital-solutions/Generamba/tree/0.7.2) (2016-01-10)
165 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/0.7.1...0.7.2)
166 |
167 | **Fixed bugs:**
168 |
169 | - Don't set target in swift projects [\#65](https://github.com/rambler-digital-solutions/Generamba/issues/65)
170 | - Errors if default path is empty [\#64](https://github.com/rambler-digital-solutions/Generamba/issues/64)
171 | - Default template set can not be used [\#60](https://github.com/rambler-digital-solutions/Generamba/issues/60)
172 |
173 | ## [0.7.1](https://github.com/rambler-digital-solutions/Generamba/tree/0.7.1) (2015-12-20)
174 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/0.7.0...0.7.1)
175 |
176 | ## [0.7.0](https://github.com/rambler-digital-solutions/Generamba/tree/0.7.0) (2015-12-13)
177 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/0.6.2...0.7.0)
178 |
179 | ## [0.6.2](https://github.com/rambler-digital-solutions/Generamba/tree/0.6.2) (2015-11-25)
180 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/0.6.1...0.6.2)
181 |
182 | ## [0.6.1](https://github.com/rambler-digital-solutions/Generamba/tree/0.6.1) (2015-11-21)
183 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/0.6.0...0.6.1)
184 |
185 | ## [0.6.0](https://github.com/rambler-digital-solutions/Generamba/tree/0.6.0) (2015-11-15)
186 | [Full Changelog](https://github.com/rambler-digital-solutions/Generamba/compare/0.5.0...0.6.0)
187 |
188 | ## [0.5.0](https://github.com/rambler-digital-solutions/Generamba/tree/0.5.0) (2015-11-01)
189 |
190 |
191 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
192 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # Specify your gem's dependencies in generamba.gemspec
4 | gemspec
5 |
6 | gem 'rspec', '~> 3.0'
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Egor Tolstoy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | [](https://travis-ci.org/rambler-digital-solutions/Generamba)
6 | [](https://badge.fury.io/rb/generamba)
7 | [](https://codeclimate.com/github/rambler-digital-solutions/Generamba)
8 |
9 | **Generamba** is a code generator made for working with Xcode. Primarily it is designed to generate VIPER modules but it is quite easy to customize it for generation of any other classes (both in Objective-C and Swift).
10 |
11 | *We keep evolving Generamba:*
12 | - [Vision](https://github.com/rambler-digital-solutions/Generamba/blob/develop/VISION.md),
13 | - [Changelog](https://github.com/rambler-digital-solutions/Generamba/blob/develop/CHANGELOG.md),
14 | - [Release notes](https://github.com/rambler-digital-solutions/Generamba/releases).
15 |
16 | Besides, we started working on 2.0 version with powerful DSL and plugins. Check the [release roadmap](https://github.com/rambler-digital-solutions/Generamba/blob/develop/docs/2.x/roadmap.md)!
17 |
18 | 
19 |
20 | ### Key features
21 |
22 | - Supports work with *.xcodeproj* files out of the box. All generated class files are automatically placed to specific folders and groups of Xcode project.
23 | - Can generate both code itself and tests adding them to right targets.
24 | - Based on work with [liquid-templates](https://github.com/Shopify/liquid) that have plain and readable syntax in comparison with templates for Xcode.
25 | - It is very easy to create a new module: `generamba gen [MODULE_NAME] [TEMPLATE_NAME]`. You do not need to input a bunch of data each time because each project corresponds to only one configuration file that holds standard file system and Xcode-project pathes, names of targets, information about the author.
26 |
27 | ### Installation
28 |
29 | > Ruby 2.2 or later version is required. To check your current Ruby version run this command in terminal:
30 | ```bash
31 | $ ruby --version
32 | ```
33 | When necessary you can install the required Ruby version with the help of [`rvm`](http://octopress.org/docs/setup/rvm/) or [`rbenv`](http://octopress.org/docs/setup/rbenv/).
34 |
35 | Run the command `gem install generamba`.
36 |
37 | ### Usage
38 | 1. Run [`generamba setup`](https://github.com/rambler-digital-solutions/Generamba/wiki/Available-Commands#basic-generamba-configuration) in the project root folder. This command helps to create [Rambafile](https://github.com/rambler-digital-solutions/Generamba/wiki/Rambafile-Structure) that define all configuration needed to generate code. You can modify this file directly in future.
39 | 2. Add all templates planned to use in the project to the generated [Rambafile](https://github.com/rambler-digital-solutions/Generamba/wiki/Rambafile-Structure). You can begin with one of the templates from our catalog: `{name: 'rviper_controller'}`.
40 | 3. Run [`generamba template install`](https://github.com/rambler-digital-solutions/Generamba/wiki/Available-Commands#template-installation). All the templates will be placed in the '/Templates' folder of your current project.
41 | 4. Run [`generamba gen [MODULE_NAME] [TEMPLATE_NAME]`](https://github.com/rambler-digital-solutions/Generamba/wiki/Available-Commands#module-generation) - It creates module with specific name from specific template.
42 |
43 | ### Additional info
44 |
45 | Run `generamba help` to learn more about each of the Generamba features.
46 |
47 | **Wiki:**
48 | - [Command list](https://github.com/rambler-digital-solutions/Generamba/wiki/Available-Commands)
49 | - [Understanding the Rambafile](https://github.com/rambler-digital-solutions/Generamba/wiki/Rambafile-Structure)
50 | - [Understanding templates](https://github.com/rambler-digital-solutions/Generamba/wiki/Template-Structure)
51 |
52 | **Other materials:**
53 | - [Russian] Rambler.iOS V: Generamba and Code Generation ([Slides](http://www.slideshare.net/Rambler-iOS/viper-56423582) | [Video](http://www.youtube.com/watch?v=NXNiN9FaUnY))
54 | - [Introduction to Generamba](http://etolstoy.com/2016/02/10/generamba/)
55 |
56 | ### Authors
57 |
58 | - Egor Tolstoy, Beniamin Sarkisyan, Andrey Zarembo and the rest of [Rambler.iOS team](https://github.com/orgs/rambler-digital-solutions/teams/ios-team).
59 |
60 | ### License
61 |
62 | MIT
63 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require "bundler/gem_tasks"
2 | require "rspec/core/rake_task"
3 |
4 | RSpec::Core::RakeTask.new(:spec)
5 |
6 | task :default => :spec
7 |
--------------------------------------------------------------------------------
/VISION.md:
--------------------------------------------------------------------------------
1 | # Vision
2 |
3 | Generamba is a tool with one primary role:
4 |
5 | > Routine tasks automation through code generation.
6 |
7 | At first it was designed to work only with Xcode - IDE for iOS/macOS, but as time passed we saw a lot of opportunities to use it in other circumstances, e.g. in frontend, Android and backend development.
8 |
9 | ### What Is Generamba
10 |
11 | The Generamba core is a simple generator that takes a [liquid](https://shopify.github.io/liquid/) template and a set of parameters as an input and produces a text snippet as an output. Everything else is built upon this simple concept.
12 |
13 | There are a lot of IDE's, package managers and other stuff which is related to creating new code modules. We try to keep the core small but provide rich opportunities for integration with all these tools via plugins *(in development)* and templates *(ready to use)* systems.
14 |
15 | ### General Aim
16 |
17 | Our general aim is to provide a simple yet extensible way to generate any piece of code. The beginner should be able to create new code modules without complex configuration process. Generamba capabilities should grow as fast as the user needs, providing ways to validate the environment status, integrations with different file systems and IDEs, complex statements inside templates and so on.
18 |
19 | ### Templates
20 |
21 | Code templates are the fuel for Generamba. We use a [liquid](https://shopify.github.io/liquid/) markup, because of its beautiful syntax and the ability to implement really complex logic.
22 |
23 | Templates may be private as well as adopted for public. We provide a number of ways to install them - using local paths, remote git repository, public or private catalogs.
24 |
25 | We also maintain a [public catalog](https://github.com/rambler-digital-solutions/generamba-catalog) which has some popular templates for iOS/macOS projects.
26 |
27 | ### Communication
28 |
29 | We try to keep all the discussion about Generamba within [GitHub issues](https://github.com/rambler-digital-solutions/Generamba/issues). This attitude allows us to keep our processes and intentions transparent.
30 |
31 | Besides it there is a private Telegram channel where maintainers discuss work questions. We are considering moving to Slack or Gitter at some point in the future - but we haven't grown big enough yet.
32 |
33 | ### Contributions
34 |
35 | Despite main maintainers are engineers from Rambler&Co team, we are glad to welcome external contributors. Generamba has evolved a lot since the first alpha release thanks to a lot of ideas from its users that came in the form of issues and pull requests.
36 |
37 | The aim of our core team is to adopt Generamba possibilities to each user needs and provide him a way to extend its functionality himself.
38 |
39 | ### ...
40 |
41 | The structure and idea of *VISION.md* file was taken from the [Danger](https://github.com/danger/danger) project and [@orta](https://github.com/orta).
42 |
--------------------------------------------------------------------------------
/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require "bundler/setup"
4 | require "generamba"
5 |
6 | # You can add fixtures and/or initialization code here to make experimenting
7 | # with your gem easier. You can also use a different console, if you like.
8 |
9 | # (If you use this, don't forget to add pry to your Gemfile!)
10 | # require "pry"
11 | # Pry.start
12 |
13 | require "irb"
14 | IRB.start
15 |
--------------------------------------------------------------------------------
/bin/generamba:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require 'generamba'
4 |
5 | Generamba::CLI::Application.start(ARGV)
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -euo pipefail
3 | IFS=$'\n\t'
4 |
5 | bundle install
6 |
7 | # Do any other automated setup that you need to do here
8 |
--------------------------------------------------------------------------------
/docs/2.x/roadmap.md:
--------------------------------------------------------------------------------
1 | # Generamba 2.0 Roadmap
2 | ### Overview
3 |
4 | The main aim of 2.0 release is to decouple Generamba from iOS/macOS development and make it available for other areas as well: backend, frontend, Android.
5 |
6 | We'll definitely break the backwards compatibility with *Rambafile* and templates created for the 1.x Generamba versions. To simplify the upgrading process we're considering writing some automatic migration tools.
7 |
8 | ### High-Level Tasks
9 |
10 | * Switch *Rambafile* from `yml` to a custom DSL format.
11 | * Wrap repetitive tasks into *ramba*'s - the nearest analogs are *lane*'s from `fastlane`.
12 | * Introduce the concept of two types of *plugins*: system (validation, save) and general-purpose.
13 | * Allow the usage of different types of hooks - `before`, `after`, `error`.
14 | * Add validation plugins, that are available to check the environment before code generation.
15 | * Extract the saving logic from the Generamba core to plugins, both to filesystem and Xcode.
16 | * Add saving plugins, that are available to process the text snippet created by generamba and save it somewhere.
17 | * Extract the validation logic from the Generamba core to plugins, both for CocoaPods and Carthage.
18 |
19 | ### Generamba Flow
20 |
21 | A typical generation process consists of three steps:
22 | * validation
23 | * generation
24 | * saving
25 |
26 | #### Validation
27 |
28 | That step is used to validate the environment status before code generation. It's a perfect place to implement logic of checking the required packages versions, the presence of system libraries, git status and so on.
29 |
30 | If one of checks returns an error, the overall validation process doesn't stop until all of validation methods execute. This is crucial for a smooth user experience.
31 |
32 | #### Generation
33 |
34 | That's the core functionality of Generamba. A user provides a template name and some options which are used as an input. After the generation Generamba produces a text snippet as an output.
35 |
36 | There can be multiple generation actions as well. All of them are executed in the writing order and their results are stored in-memory.
37 |
38 | #### Saving
39 |
40 | This step defines what to do with a generation output. The most obvious options are to store it as a file in some directory on the disk, embed it in your IDE, upload somewhere or print in log.
41 |
42 | If there are multiple saving actions, each of them is applied to each generation output. They are executed in the writing order.
43 |
44 | ### DSL
45 |
46 | #### Basic Rambafile Structure
47 |
48 | The main building block of *Rambafile* is `ramba`:
49 |
50 | ```
51 | desc "Creates a new Xcode project"
52 | ramba :viper_module do
53 | # Detailed description of generation steps
54 | end
55 | ```
56 |
57 | The *Rambafile* may be monolithic as well as decomposed to multiple files. This is available via special functions:
58 | - `ramba_import_local('path')` - imports the contents of `Rambafile` stored locally.
59 | - `ramba_import_git('git', 'branch')` - imports the contents of Rambafile stored in remote git repository.
60 |
61 | #### Setting Options
62 |
63 | A user can set options in any part of *Rambafile* structure. It's important to note, that option, defined on the next level of method hierarchy, overwrites it's previous declaration. That allows to have a default value for some key and redefine it in each `ramba`.
64 | ```
65 | set :project_name, 'MyProject'
66 |
67 | ramba :viper_module do
68 | set :project_name, 'MyProject'
69 | end
70 | ```
71 |
72 | It's also available to set an option using lambda:
73 | ```
74 | set :date_string, -> {
75 | "Current date: #{Date.now}"
76 | }
77 | ```
78 |
79 | > How options are set in Rambafile...
80 | >
81 |
82 | Besides `ramba` -specific options, there are template-specific options as well. They may correspond to a specific template and be defined in the *.rambaspec* file.
83 |
84 | > The saving action for Xcode should behave differently depending on whether a generated file it's a code file or some resource. So, there is a special option for each file of Xcode templates:
85 | > `- {name: Router/RouterTests.m, path: Tests/Router/router_tests.m.liquid, is_resource: false}`
86 |
87 | #### Hooks
88 |
89 | There are multiple types of hooks, which make possible to perform some action or redefine an option in certain moments of generation cycle.
90 |
91 | ##### `before` hooks
92 |
93 | A user can specify a hook, that'll execute before a specific `ramba`:
94 | ```
95 | before :viper_module do
96 | # Some logic here...
97 | end
98 | ```
99 |
100 | It's also possible to write a hook that'll execute before each `ramba`:
101 | ```
102 | before_each do |ramba_name|
103 | # Some logic here...
104 | end
105 | ```
106 |
107 | ##### `after` hooks
108 |
109 | A user can specify a hook, that'll execute after a specific `ramba`:
110 | ```
111 | after :viper_module do
112 | # Some logic here...
113 | end
114 | ```
115 |
116 | It's also possible to write a hook that'll execute after each `ramba`:
117 | ```
118 | after_each do |ramba_name|
119 | # Some logic here...
120 | end
121 | ```
122 |
123 | ##### `error` hooks
124 |
125 | If any action returns an error, it's possible to customize the resulting behavior for a specific `ramba` :
126 | ```
127 | error :viper_module do
128 | # Some logic here...
129 | end
130 | ```
131 | It's also possible to write a hook that'll execute in case of error in any `ramba`:
132 | ```
133 | error_each do |ramba_name|
134 | # Some logic here...
135 | end
136 | ```
137 |
138 | #### `ramba` structure
139 |
140 | As we've already mentioned, `ramba` consists of three main steps. Multiple actions in each step are executed in the writing order.
141 |
142 | ##### Validation actions
143 |
144 | ```
145 | ramba :viper_module do
146 | ...
147 | validate :validate_plugin_name do
148 | set :some_option, 'some_value'
149 | any_custom_action()
150 | end
151 | ...
152 | end
153 | ```
154 |
155 | This notation means the following steps:
156 | - The lambda passed to the validate action is executed.
157 | - The plugin with name `validate_plugin_name` is called with options modified by lambda.
158 |
159 | The notation can be simplified to:
160 | ```
161 | validate :validate_plugin_name
162 | ```
163 |
164 | ##### Generation actions
165 |
166 | ```
167 | ramba :viper_module do
168 | ...
169 | gen :viper_module do
170 | set :some_option, 'some_value'
171 | any_custom_action(parameter1)
172 | end
173 | ...
174 | end
175 | ```
176 |
177 | This notation means the following steps:
178 | - The lambda passed to the gen action is executed.
179 | * The `gen` command is called with a template *viper_module* and options modified by lambda.
180 |
181 | The notation can be simplified to:
182 | ```
183 | gen :viper_module
184 | ```
185 |
186 | ##### Saving actions
187 |
188 | ```
189 | ramba :viper_module do
190 | ...
191 | save :save_plugin_name do
192 | set :some_option, 'some_value'
193 | any_custom_action()
194 | end
195 | ...
196 | end
197 | ```
198 |
199 | This notation means the following steps:
200 | - The lambda passed to the saving action is executed.
201 | - The plugin with name `save_plugin_name` is called with options modified by lambda.
202 |
203 | The notation can be simplified to:
204 | ```
205 | save :save_plugin_name
206 | ```
207 |
208 | ##### Custom Actions
209 |
210 | Besides system plugins (validation and saving), a user can create a general-purpose plugin which contains some specific reusable logic. E.g. a plugin which clears the environment - calls `git reset`, uninstalls some packages and so on. It's called simply by calling it's name:
211 | ```
212 | ramba :viper_module do
213 | ...
214 | any_custom_action()
215 | ...
216 | end
217 | ```
218 |
219 | ##### Templates and Catalogs
220 |
221 | Templates and tempalte catalogs, used for code generation, can be specified right in the `ramba`'s.
222 |
223 | ```
224 | ramba :viper_module do
225 | catalog 'https://github.com/user/catalog', branch:'develop'
226 | template 'viper_ios', version:'1.2.5'
227 | template 'viper_ios2', path:'/local_templates'
228 | end
229 | ```
230 |
231 | - `catalog` keyword specifies a custom template catalog (like https://github.com/rambler-digital-solutions/generamba-catalog).
232 | - `branch` parameter specifies a concrete catalog branch
233 | - `template` keyword declares a template that needs to be installed
234 | - `version` parameter specifies a concrete template version.
235 | - `path` parameter specifies a local path to the template.
236 | - `git` parameter specifies a remote repository path to a template.
237 | - `branch` parameter is used together with `git` to specify a branch.
238 |
239 | The `generamba template install` command aggregates all of the templates from the `Rambafile` and installs them in a `.generamba` hidden directory. When a user triggers some `ramba`, templates are loaded from this directory. The only exception are local templates - they are always installed from the specified in the `Rambafile` local path.
240 |
241 | ### Plugins
242 |
243 | The main ideas behind plugin system are:
244 |
245 | - Increase code reusability between different projects,
246 | * Keep the Generamba core as simple as possible,
247 | * Abstract from specific implementations of different IDEs,
248 | * Allow users to easily extend Generamba functionality for their needs.
249 |
250 | As we've already mentioned, there are two types of plugins:
251 |
252 | - System plugins - validation and saving,
253 | * Custom plugins.
254 |
255 | The main difference between them is how system calls them during `ramba` execution.
256 |
257 | #### Plugin Structure
258 |
259 | ```
260 | module Generamba
261 | module Plugins
262 | class CocoaPodsPackageVersionValidationPlugin < ValidationPlugin
263 | # The main body of a plugin
264 | def self.run(params)
265 | # Loads Podfile
266 | # Analyzez dependencies version
267 | # Compares these versions to the passed options
268 | end
269 |
270 | # The description of what this plugin does
271 | def self.description
272 | 'Verifies dependencies version in the project Podfile'
273 | end
274 |
275 | # Explicitly declaring available plugin options
276 | def self.available_options
277 | [
278 | Generamba::ConfigItem.new(key: :package_versions,
279 | description: "The hash with dependencies names and required versions",
280 | default_value: [])
281 | ]
282 | end
283 |
284 | # Declaring the output parameters
285 | def self.output
286 | [
287 | ['COCOAPODS_CHECK_RESULT', 'The result of dependency checking']
288 | ]
289 | end
290 |
291 | # Who created this plugin
292 | def self.authors
293 | ["etolstoy"]
294 | end
295 | end
296 | end
297 | end
298 | ```
299 |
300 | The same structure applies to other kinds of plugins. The only difference is the base class for the plugin - it can be `ValidationPlugin`, `SavingPlugin`, `Plugin`.
301 |
302 | We've borrowed the plugin structure from `fastlane`.
303 |
304 | #### Plugin Distribution
305 |
306 | To avoid over-engineering in this version plugins will be distributed together with Generamba binary. If there'll be a lot of community-created plugins, will think about switching to other distribution system.
307 |
308 | It's also possible to store plugins near the `Rambafile` in a separate directory `/plugins`. They'll be loaded by Generamba automatically.
309 |
310 | ### Rambafile Example
311 |
312 | ```
313 | ramba_import_local('path')
314 | ramba_import_git('git', 'branch')
315 |
316 | set :project_name, 'LiveJournal'
317 |
318 | before :viper_module do
319 | set :company, 'Rambler&Co'
320 | set :xcodeproj_path, 'LiveJournal.xcodeproj'
321 | set :project_targets, ['LiveJournal1', 'LiveJournal2']
322 | set :test_target, 'LiveJournalTests'
323 | end
324 |
325 | desc "Creates a simple VIPER module"
326 | ramba :viper_module do
327 | validate :plugin_validate_name do
328 | set :some_option, '456'
329 | any_custom_action()
330 | end
331 |
332 | gen :template_name do
333 | set :some_option, '123'
334 | any_custom_action(parameter1)
335 | end
336 |
337 | save :file_system do
338 | set :some_option, '789'
339 | end
340 |
341 | save :xcode_proj
342 | end
343 |
344 | desc "Creates a new Xcode project"
345 | ramba :create_project do
346 | sh("liftoff") # Calling a shell script which invokes a 'liftoff' utility
347 | add_pods(["Typhoon", "MagicalRecord"])
348 |
349 | gen :app_delegate
350 | gen :core_data_stack
351 |
352 | save :file_system
353 | save :xcode_proj
354 | end
355 |
356 | # It's called after each 'ramba' execution
357 | after_each do |ramba_name|
358 | # Some logic here
359 | end
360 |
361 | # It's called in case of an error in any 'ramba'
362 | error :viper_module do
363 | # Some error handling logic here
364 | end
365 | ```
366 |
--------------------------------------------------------------------------------
/generamba.gemspec:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | lib = File.expand_path('../lib', __FILE__)
3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4 | require 'generamba/version'
5 |
6 | Gem::Specification.new do |spec|
7 | spec.name = 'generamba'
8 | spec.version = Generamba::VERSION
9 | spec.authors = ['Egor Tolstoy', 'Andrey Zarembo', 'Beniamin Sarkisyan', 'Aleksandr Sychev']
10 | spec.email = 'rambler.ios@rambler-co.ru'
11 |
12 | spec.summary = 'Advanced code generator for Xcode projects with a nice and flexible template system.'
13 | spec.description = 'Generamba is a powerful and easy-to-use Xcode code generator. It provides a project-based configuration, flexible templates system, the ability to generate code and tests simultaneously.'
14 | spec.homepage = 'https://github.com/rambler-digital-solutions/Generamba'
15 | spec.license = 'MIT'
16 |
17 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18 | spec.executables = ['generamba']
19 | spec.require_paths = ['lib']
20 |
21 | spec.required_ruby_version = '>= 2.2'
22 |
23 | spec.add_runtime_dependency 'thor', '0.19.1'
24 | spec.add_runtime_dependency 'xcodeproj', '>= 1.6.0', '< 2.0.0'
25 | spec.add_runtime_dependency 'liquid', '4.0.0'
26 | spec.add_runtime_dependency 'git', '1.2.9.1'
27 | spec.add_runtime_dependency 'cocoapods-core', '>= 1.4.0', '< 2.0.0'
28 | spec.add_runtime_dependency 'terminal-table', '1.4.5'
29 |
30 | spec.add_development_dependency 'bundler', '~> 1.10'
31 | spec.add_development_dependency 'rake', '~> 10.0'
32 | spec.add_development_dependency 'rspec', '~> 3.4'
33 | spec.add_development_dependency 'fakefs', '~> 0.6.1'
34 | # ActiveSupport dependency is not used by dashramba; instead some other dependency
35 | # requires it. We lock it to 4.2.7 so as to avoid using 5.0, which is
36 | # not compatible with older versions of Ruby.
37 | spec.add_development_dependency 'activesupport', '~> 4.2', '>= 4.2.7'
38 | end
39 |
--------------------------------------------------------------------------------
/lib/generamba.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 | require 'generamba/constants/constants.rb'
3 | require 'generamba/constants/rambafile_constants.rb'
4 | require 'generamba/constants/rambaspec_constants.rb'
5 | require 'generamba/cli/cli.rb'
6 | require 'generamba/code_generation/code_module.rb'
7 | require 'generamba/code_generation/module_template.rb'
8 | require 'generamba/code_generation/content_generator.rb'
9 | require 'generamba/code_generation/rambafile_generator.rb'
10 | require 'generamba/module_generator.rb'
11 | require 'generamba/template/processor/template_processor.rb'
12 | require 'generamba/template/installer/template_installer_factory'
13 | require 'generamba/configuration/user_preferences.rb'
14 | require 'generamba/template/creator/template_creator.rb'
15 | require 'generamba/tools/string-colorize.rb'
16 | end
--------------------------------------------------------------------------------
/lib/generamba/cli/cli.rb:
--------------------------------------------------------------------------------
1 | require 'thor'
2 | require 'xcodeproj'
3 | require 'liquid'
4 | require 'git'
5 | require 'generamba/cli/gen_command.rb'
6 | require 'generamba/cli/setup_command.rb'
7 | require 'generamba/cli/version_command.rb'
8 | require 'generamba/cli/setup_username_command.rb'
9 | require 'generamba/cli/thor_extension.rb'
10 | require 'generamba/cli/template/template_group.rb'
11 |
12 | module Generamba::CLI
13 | class Application < Thor
14 |
15 | end
16 | end
--------------------------------------------------------------------------------
/lib/generamba/cli/gen_command.rb:
--------------------------------------------------------------------------------
1 | require 'thor'
2 | require 'generamba/helpers/print_table.rb'
3 | require 'generamba/helpers/rambafile_validator.rb'
4 | require 'generamba/helpers/xcodeproj_helper.rb'
5 | require 'generamba/helpers/dependency_checker.rb'
6 | require 'generamba/helpers/gen_command_table_parameters_formatter.rb'
7 | require 'generamba/helpers/module_validator.rb'
8 | require 'generamba/helpers/module_info_generator.rb'
9 |
10 | module Generamba::CLI
11 | class Application < Thor
12 |
13 | include Generamba
14 |
15 | desc 'gen [MODULE_NAME] [TEMPLATE_NAME]', 'Creates a new VIPER module with a given name from a specific template'
16 | method_option :description, :aliases => '-d', :desc => 'Provides a full description to the module'
17 | method_option :author, :desc => 'Specifies the author name for generated module'
18 | method_option :project_targets, :desc => 'Specifies project targets for adding new module files'
19 | method_option :project_file_path, :desc => 'Specifies a location in the filesystem for new files'
20 | method_option :project_group_path, :desc => 'Specifies a location in Xcode groups for new files'
21 | method_option :module_path, :desc => 'Specifies a location (both in the filesystem and Xcode) for new files'
22 | method_option :test_targets, :desc => 'Specifies project targets for adding new test files'
23 | method_option :test_file_path, :desc => 'Specifies a location in the filesystem for new test files'
24 | method_option :test_group_path, :desc => 'Specifies a location in Xcode groups for new test files'
25 | method_option :test_path, :desc => 'Specifies a location (both in the filesystem and Xcode) for new test files'
26 | method_option :custom_parameters, :type => :hash, :default => {}, :desc => 'Specifies extra parameters in format `key1:value1 key2:value2` for usage during code generation'
27 | def gen(module_name, template_name)
28 | does_rambafile_exist = Dir[RAMBAFILE_NAME].count > 0
29 |
30 | unless does_rambafile_exist
31 | puts('Rambafile not found! Run `generamba setup` in the working directory instead!'.red)
32 | return
33 | end
34 |
35 | rambafile_validator = Generamba::RambafileValidator.new
36 | rambafile_validator.validate(RAMBAFILE_NAME)
37 |
38 | setup_username_command = Generamba::CLI::SetupUsernameCommand.new
39 | setup_username_command.setup_username
40 |
41 | rambafile = YAML.load_file(RAMBAFILE_NAME)
42 |
43 | code_module = CodeModule.new(module_name, rambafile, options)
44 |
45 | module_validator = ModuleValidator.new
46 | module_validator.validate(code_module)
47 |
48 | module_info = ModuleInfoGenerator.new(code_module)
49 | template = ModuleTemplate.new(template_name, module_info.scope)
50 |
51 | parameters = GenCommandTableParametersFormatter.prepare_parameters_for_displaying(code_module, template_name)
52 | PrintTable.print_values(
53 | values: parameters,
54 | title: "Summary for gen #{module_name}"
55 | )
56 |
57 | DependencyChecker.check_all_required_dependencies_has_in_podfile(template.dependencies, code_module.podfile_path)
58 | DependencyChecker.check_all_required_dependencies_has_in_cartfile(template.dependencies, code_module.cartfile_path)
59 |
60 | project = XcodeprojHelper.obtain_project(code_module.xcodeproj_path)
61 | module_group_already_exists = XcodeprojHelper.module_with_group_path_already_exists(project, code_module.project_group_path, code_module.create_logical_groups)
62 |
63 | if module_group_already_exists
64 | replace_exists_module = yes?("#{module_name} module already exists. Replace? (yes/no)")
65 |
66 | unless replace_exists_module
67 | return
68 | end
69 | end
70 |
71 | generator = Generamba::ModuleGenerator.new
72 | generator.generate_module(module_name, code_module, template)
73 | end
74 |
75 | end
76 | end
--------------------------------------------------------------------------------
/lib/generamba/cli/setup_command.rb:
--------------------------------------------------------------------------------
1 | require 'thor'
2 | require 'xcodeproj'
3 | require 'liquid'
4 | require 'git'
5 | require 'generamba/constants/rambafile_constants.rb'
6 | require 'generamba/helpers/print_table.rb'
7 |
8 | module Generamba::CLI
9 | class Application < Thor
10 | include Generamba
11 |
12 | desc 'setup', 'Creates a Rambafile with a config for a given project'
13 | def setup
14 | properties = {}
15 |
16 | setup_username_command = Generamba::CLI::SetupUsernameCommand.new
17 | setup_username_command.setup_username
18 |
19 | properties[COMPANY_KEY] = ask('The company name which will be used in the headers:')
20 |
21 | project_name = Pathname.new(Dir.getwd).basename.to_s
22 | is_right_project_name = yes?("The name of your project is #{project_name}. Do you want to use it? (yes/no)")
23 |
24 | properties[PROJECT_NAME_KEY] = is_right_project_name ? project_name : ask_non_empty_string('The project name:', 'Project name should not be empty')
25 | properties[PROJECT_PREFIX_KEY] = ask('The project prefix (if any):')
26 |
27 | xcodeproj_path = ask_file_with_path('*.xcodeproj',
28 | '.xcodeproj file of the project')
29 |
30 | properties[XCODEPROJ_PATH_KEY] = xcodeproj_path
31 | project = Xcodeproj::Project.open(xcodeproj_path)
32 |
33 | targets_prompt = ''
34 | project.targets.each_with_index { |element, i| targets_prompt += ("#{i}. #{element.name}" + "\n") }
35 | project_target = ask_index("Select the appropriate target for adding your MODULES (type the index):\n" + targets_prompt,project.targets)
36 | include_tests = yes?('Are you using unit-tests in this project? (yes/no)')
37 |
38 | test_target = nil
39 |
40 | if include_tests
41 | test_target = ask_index("Select the appropriate target for adding your TESTS (type the index):\n" + targets_prompt,project.targets)
42 | end
43 |
44 | should_add_all_modules_by_one_path = yes?('Do you want to add all your modules by one path? (yes/no)')
45 |
46 | project_file_path = nil
47 | project_group_path = nil
48 |
49 | test_file_path = nil
50 | test_group_path = nil
51 |
52 | create_logical_groups = nil
53 |
54 | if should_add_all_modules_by_one_path || include_tests
55 | should_use_same_paths = false
56 |
57 | if should_add_all_modules_by_one_path
58 | should_use_same_paths = yes?('Do you want to use the same paths for your files both in Xcode and the filesystem? (yes/no)')
59 | end
60 |
61 | if should_use_same_paths
62 | if should_add_all_modules_by_one_path
63 | project_group_path = ask('The default path for creating new modules:')
64 | project_file_path = project_group_path
65 | end
66 |
67 | if include_tests
68 | test_group_path = ask('The default path for creating tests:')
69 | test_file_path = test_group_path
70 | end
71 | else
72 | if should_add_all_modules_by_one_path
73 | project_group_path = ask('The default path for creating new modules (in Xcode groups):')
74 | project_file_path = ask('The default path for creating new modules (in the filesystem):')
75 | end
76 |
77 | if include_tests
78 | test_group_path = ask('The default path for creating tests (in Xcode groups):')
79 | test_file_path = ask('The default path for creating tests (in the filesystem):')
80 | end
81 | end
82 | end
83 |
84 | create_logical_groups = yes?('Do you want to create Groups in Xcode without folders in filesystem? (yes/no)')
85 |
86 | using_pods = yes?('Are you using Cocoapods? (yes/no)')
87 | if using_pods
88 | properties[PODFILE_PATH_KEY] = ask_file_with_path('Podfile', 'Podfile')
89 | end
90 |
91 | using_carthage = yes?('Are you using Carthage? (yes/no)')
92 | if using_carthage
93 | properties[CARTFILE_PATH_KEY] = ask_file_with_path('Cartfile', 'Cartfile')
94 | end
95 |
96 | should_add_templates = yes?('Do you want to add some well known templates to the Rambafile? (yes/no)')
97 | if should_add_templates
98 | properties[TEMPLATES_KEY] = [
99 | '{name: rviper_controller}',
100 | '{name: mvvm_controller}',
101 | '{name: swifty_viper}'
102 | ]
103 | end
104 |
105 | properties[PROJECT_TARGET_KEY] = project_target.name if project_target
106 | properties[PROJECT_FILE_PATH_KEY] = project_file_path if project_file_path
107 | properties[PROJECT_GROUP_PATH_KEY] = project_group_path if project_group_path
108 | properties[TEST_TARGET_KEY] = test_target.name if test_target
109 | properties[TEST_FILE_PATH_KEY] = test_file_path if test_file_path
110 | properties[TEST_GROUP_PATH_KEY] = test_group_path if test_group_path
111 | properties[CREATE_LOGICAL_GROUPS_KEY] = create_logical_groups if create_logical_groups
112 |
113 | PrintTable.print_values(
114 | values: properties,
115 | title: 'Summary for generamba setup'
116 | )
117 |
118 | Generamba::RambafileGenerator.create_rambafile(properties)
119 | if should_add_templates
120 | puts('Rambafile successfully created! Now run `generamba template install`.'.green)
121 | else
122 | puts('Rambafile successfully created!\n Go on and find some templates in our catalog using `generamba template list` command.\n Add any of them to the Rambafile and run `generamba template install`.'.green)
123 | end
124 |
125 | end
126 | end
127 | end
--------------------------------------------------------------------------------
/lib/generamba/cli/setup_username_command.rb:
--------------------------------------------------------------------------------
1 | module Generamba::CLI
2 | class SetupUsernameCommand < Thor
3 |
4 | no_commands {
5 | def setup_username
6 | username = Generamba::UserPreferences.obtain_username
7 | unless username
8 | puts('The author name is not configured!'.red)
9 | git_username = Git.init.config['user.name']
10 | if git_username != nil && yes?("Your name in git is configured as #{git_username}. Do you want to use it in code headers? (yes/no)")
11 | username = git_username
12 | else
13 | username = ask_non_empty_string('The author name which will be used in the headers:', 'User name should not be empty')
14 | end
15 | Generamba::UserPreferences.save_username(username)
16 | end
17 |
18 | end
19 | }
20 | end
21 | end
--------------------------------------------------------------------------------
/lib/generamba/cli/template/template_create_command.rb:
--------------------------------------------------------------------------------
1 | require 'generamba/helpers/print_table.rb'
2 |
3 | module Generamba::CLI
4 | class Template < Thor
5 | include Generamba
6 |
7 | desc 'create [TEMPLATE_NAME]', 'Creates a new Generamba template with a given name'
8 | def create(template_name)
9 | summary = ask('The brief description of your new template:')
10 | author = ask('Who is the author of this template:')
11 | license = ask('What license will be used (e.g. MIT):')
12 |
13 | has_dependencies = yes?('Will your template contain any third-party dependencies (available via Cocoapods or Carthage)? (yes/no)')
14 | if has_dependencies
15 | dependencies = ask_loop('Enter the name of your dependency (empty string to stop):')
16 | end
17 |
18 | properties = {
19 | TEMPLATE_NAME_KEY => template_name,
20 | TEMPLATE_SUMMARY_KEY => summary,
21 | TEMPLATE_AUTHOR_KEY => author,
22 | TEMPLATE_LICENSE_KEY => license
23 | }
24 |
25 | if dependencies and !dependencies.empty?
26 | properties[TEMPLATE_DEPENDENCIES_KEY] = dependencies
27 | end
28 |
29 | PrintTable.print_values(
30 | values: properties,
31 | title: "Summary for template create"
32 | )
33 |
34 | template_creator = Generamba::TemplateCreator.new
35 | template_creator.create_template(properties)
36 | puts("The template #{template_name} is successfully generated! Now add some file templates into it.".green)
37 | end
38 |
39 | end
40 | end
--------------------------------------------------------------------------------
/lib/generamba/cli/template/template_group.rb:
--------------------------------------------------------------------------------
1 | require 'generamba/cli/template/template_install_command.rb'
2 | require 'generamba/cli/template/template_create_command.rb'
3 | require 'generamba/cli/template/template_list_command.rb'
4 | require 'generamba/cli/template/template_search_command.rb'
5 |
6 | module Generamba::CLI
7 | class Application < Thor
8 | register(Generamba::CLI::Template, 'template', 'template ', 'Provides a set of commands for working with templates')
9 | end
10 |
11 | class Template < Thor
12 |
13 | end
14 | end
--------------------------------------------------------------------------------
/lib/generamba/cli/template/template_install_command.rb:
--------------------------------------------------------------------------------
1 | module Generamba::CLI
2 | class Template < Thor
3 |
4 | desc 'install', 'Installs all the templates specified in the Rambafile from the current directory'
5 | def install
6 | does_rambafile_exist = Dir[RAMBAFILE_NAME].count > 0
7 |
8 | unless does_rambafile_exist
9 | puts('Rambafile not found! Run `generamba setup` in the working directory instead!'.red)
10 | return
11 | end
12 |
13 | catalog_downloader = Generamba::CatalogDownloader.new
14 | installer_factory = Generamba::TemplateInstallerFactory.new
15 | template_processor = Generamba::TemplateProcessor.new(catalog_downloader, installer_factory)
16 |
17 | rambafile = YAML.load_file(RAMBAFILE_NAME)
18 | template_processor.install_templates(rambafile)
19 | end
20 | end
21 | end
--------------------------------------------------------------------------------
/lib/generamba/cli/template/template_list_command.rb:
--------------------------------------------------------------------------------
1 | require 'generamba/template/helpers/catalog_downloader'
2 | require 'generamba/template/helpers/catalog_template_list_helper'
3 |
4 | module Generamba::CLI
5 | class Template < Thor
6 | include Generamba
7 |
8 | desc 'list', 'Prints out the list of all templates available in the shared GitHub catalog'
9 | def list
10 | downloader = CatalogDownloader.new
11 | catalog_template_list_helper = CatalogTemplateListHelper.new
12 |
13 | templates = []
14 | catalog_paths = downloader.update_all_catalogs_and_return_filepaths
15 | catalog_paths.each do |path|
16 | templates += catalog_template_list_helper.obtain_all_templates_from_a_catalog(path)
17 | templates = templates.uniq
18 | end
19 |
20 | templates.each do |template_name|
21 | puts(template_name)
22 | end
23 | end
24 | end
25 | end
--------------------------------------------------------------------------------
/lib/generamba/cli/template/template_search_command.rb:
--------------------------------------------------------------------------------
1 | require 'generamba/template/helpers/catalog_downloader.rb'
2 | require 'generamba/template/helpers/catalog_template_search_helper'
3 |
4 | module Generamba::CLI
5 | class Template < Thor
6 | include Generamba
7 |
8 | desc 'search [SEARCH_STRING]', 'Searches a template with a given name in the shared GitHub catalog'
9 | def search(term)
10 | downloader = CatalogDownloader.new
11 | catalog_template_search_helper = CatalogTemplateSearchHelper.new
12 |
13 | catalog_paths = downloader.update_all_catalogs_and_return_filepaths
14 |
15 | templates = []
16 | catalog_paths.each do |path|
17 | templates += catalog_template_search_helper.search_templates_in_a_catalog(path, term)
18 | templates = templates.uniq
19 | end
20 |
21 | templates.map { |template_name|
22 | keywords = term.squeeze.strip.split(' ').compact.uniq
23 | matcher = Regexp.new('(' + keywords.join('|') + ')')
24 | template_name.gsub(matcher) { |match| "#{match}".yellow }
25 | }.each { |template_name|
26 | puts(template_name)
27 | }
28 | end
29 | end
30 | end
--------------------------------------------------------------------------------
/lib/generamba/cli/thor_extension.rb:
--------------------------------------------------------------------------------
1 | require 'thor'
2 |
3 | module Generamba::CLI
4 | class ::Thor
5 | no_commands do
6 | def ask_index(message, array)
7 | value_index = ask_with_validation(message,->(value){ (value.to_i >= 0 and value.to_i < array.count) },"Invalid selection. Please enter number from 0 to #{array.count-1}")
8 | return array[value_index.to_i]
9 | end
10 |
11 | def ask_non_empty_string(message, description = 'Value should be nonempty string')
12 | return ask_with_validation(message,->(value){value.length > 0 },description)
13 | end
14 |
15 | def ask_loop(message)
16 | array = Array.new
17 | loop do
18 | value = ask(message)
19 | break if value.empty?
20 | array.push(value)
21 | end
22 | return array
23 | end
24 |
25 | def ask_with_validation(message, is_valid_value, description = 'Invalid value')
26 | loop do
27 | value = ask(message)
28 | return value if is_valid_value.call(value)
29 | puts(description.red)
30 | end
31 | end
32 |
33 | def ask_file_with_path(pattern, message_file_name)
34 | project_files = Dir[pattern]
35 | count = project_files.count
36 | default_message = "The path to a #{message_file_name}:"
37 | if count == 1
38 | is_right_path = yes?"The path to a #{message_file_name} is '#{project_files[0]}'. Do you want to use it? (yes/no)"
39 | xcode_path = is_right_path ? project_files[0] : ask(default_message)
40 | else
41 | xcode_path = ask(default_message)
42 | end
43 | return xcode_path
44 | end
45 | end
46 | end
47 | end
--------------------------------------------------------------------------------
/lib/generamba/cli/version_command.rb:
--------------------------------------------------------------------------------
1 | require 'thor'
2 | require 'generamba/version.rb'
3 |
4 | module Generamba::CLI
5 | class Application < Thor
6 | include Generamba
7 |
8 | desc 'version', 'Prints out Generamba current version'
9 | def version
10 | options = {}
11 | options['Version'] = Generamba::VERSION.green
12 | options['Release date'] = Generamba::RELEASE_DATE.green
13 | options['Change notes'] = Generamba::RELEASE_LINK.green
14 |
15 | values = []
16 |
17 | options.each do |title, value|
18 | values.push("#{title}: #{value}")
19 | end
20 |
21 | output = values.join("\n")
22 | puts(output)
23 | end
24 | end
25 | end
--------------------------------------------------------------------------------
/lib/generamba/code_generation/Rambafile.liquid:
--------------------------------------------------------------------------------
1 | ### Headers settings
2 | company: {{ company }}
3 |
4 | ### Xcode project settings
5 | project_name: {{ project_name }}
6 | xcodeproj_path: {{ xcodeproj_path }}
7 | {% if prefix != "" %}prefix: {{ prefix }}{% endif %}
8 |
9 | {% if (project_target != nil and project_target != "") or (project_file_path != nil and project_file_path != "") or (project_group_path != nil and project_group_path != "") %}### Code generation settings section
10 | {% if project_target != nil and project_target != "" %}# The main project target name
11 | project_target: {{ project_target }}{% endif %}
12 |
13 | {% if project_file_path != nil and project_file_path != "" %}# The file path for new modules
14 | project_file_path: {{ project_file_path }}{% endif %}
15 |
16 | {% if project_group_path != nil and project_group_path != "" %}# The Xcode group path to new modules
17 | project_group_path: {{ project_group_path }}{% endif %}
18 | {% endif %}
19 |
20 | {% if (test_target != nil and test_target != "") or (test_file_path != nil and test_file_path != "") or (test_group_path != nil and test_group_path != "") %}### Tests generation settings section
21 | {% if test_target != nil and test_target != "" %}# The tests target name
22 | test_target: {{ test_target }}{% endif %}
23 |
24 | {% if test_file_path != nil and test_file_path != "" %}# The file path for new tests
25 | test_file_path: {{ test_file_path }}{% endif %}
26 |
27 | {% if test_group_path != nil and test_group_path != "" %}# The Xcode group path to new tests
28 | test_group_path: {{ test_group_path }}{% endif %}
29 | {% endif %}
30 |
31 | {% if create_logical_groups != nil and create_logical_groups %}# Create Groups in Xcode without folders in filesystem
32 | create_logical_groups: {{ create_logical_groups }} {% endif %}
33 |
34 | {% if podfile_path != nil or cartfile_path != nil %}### Dependencies settings section{% endif %}
35 | {% if podfile_path != nil %}podfile_path: {{ podfile_path }}{% endif %}
36 | {% if cartfile_path != nil %}cartfile_path: {{ cartfile_path }}{% endif %}
37 |
38 | ### Templates
39 | templates:
40 | {% if templates.size > 0 %}{% for item in templates %}- {{ item }}
41 | {% endfor %}{% else %}#- {name: local_template_name, local: 'absolute/file/path'}
42 | #- {name: remote_template_name, git: 'https://github.com/igrekde/remote_template'}
43 | #- {name: catalog_template_name}
44 | {% endif %}
--------------------------------------------------------------------------------
/lib/generamba/code_generation/code_module.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 |
3 | SLASH_REGEX = /^\/|\/$/
4 | C99IDENTIFIER = /[^\w]/
5 |
6 | PATH_TYPE_PROJECT = 'project'
7 | PATH_TYPE_TEST = 'test'
8 |
9 | # Represents currently generating code module
10 | class CodeModule
11 | attr_reader :name,
12 | :description,
13 | :author,
14 | :company,
15 | :year,
16 | :prefix,
17 | :project_name,
18 | :product_module_name,
19 | :xcodeproj_path,
20 | :project_file_path,
21 | :project_file_root,
22 | :project_group_path,
23 | :test_file_path,
24 | :test_file_root,
25 | :test_group_path,
26 | :project_targets,
27 | :test_targets,
28 | :podfile_path,
29 | :cartfile_path,
30 | :custom_parameters,
31 | :create_logical_groups
32 |
33 | def initialize(name, rambafile, options)
34 | # Base initialization
35 | @name = name
36 | @description = options[:description] ? options[:description] : "#{name} module"
37 | @author = rambafile[AUTHOR_NAME_KEY] ? rambafile[AUTHOR_NAME_KEY] : UserPreferences.obtain_username
38 | @company = rambafile[COMPANY_KEY]
39 | @year = Time.now.year.to_s
40 |
41 | @prefix = rambafile[PROJECT_PREFIX_KEY]
42 | @project_name = rambafile[PROJECT_NAME_KEY]
43 |
44 | @product_module_name = rambafile[PRODUCT_MODULE_NAME_KEY]
45 | @product_module_name = @project_name.gsub(C99IDENTIFIER, '_') if !@product_module_name && @project_name
46 |
47 | @xcodeproj_path = rambafile[XCODEPROJ_PATH_KEY]
48 |
49 | setup_file_and_group_paths(rambafile[PROJECT_FILE_PATH_KEY], rambafile[PROJECT_GROUP_PATH_KEY], PATH_TYPE_PROJECT)
50 | setup_file_and_group_paths(rambafile[TEST_FILE_PATH_KEY], rambafile[TEST_GROUP_PATH_KEY], PATH_TYPE_TEST)
51 |
52 | @create_logical_groups = rambafile[CREATE_LOGICAL_GROUPS_KEY] if rambafile[CREATE_LOGICAL_GROUPS_KEY]
53 | if create_logical_groups
54 | @project_file_root = Pathname.new(rambafile[PROJECT_FILE_PATH_KEY])
55 | @test_file_root = Pathname.new(rambafile[TEST_FILE_PATH_KEY])
56 | end
57 |
58 | @project_targets = [rambafile[PROJECT_TARGET_KEY]] if rambafile[PROJECT_TARGET_KEY]
59 | @project_targets = rambafile[PROJECT_TARGETS_KEY] if rambafile[PROJECT_TARGETS_KEY]
60 |
61 | @test_targets = [rambafile[TEST_TARGET_KEY]] if rambafile[TEST_TARGET_KEY]
62 | @test_targets = rambafile[TEST_TARGETS_KEY] if rambafile[TEST_TARGETS_KEY]
63 |
64 | # Custom parameters
65 | @custom_parameters = options[:custom_parameters]
66 |
67 | # Options adaptation
68 | @author = options[:author] if options[:author]
69 | @project_targets = options[:project_targets].split(',') if options[:project_targets]
70 | @test_targets = options[:test_targets].split(',') if options[:test_targets]
71 |
72 | setup_file_and_group_paths(options[:project_file_path], options[:project_group_path], PATH_TYPE_PROJECT)
73 | setup_file_and_group_paths(options[:test_file_path], options[:test_group_path], PATH_TYPE_TEST)
74 |
75 | # The priority is given to `module_path` and 'test_path' options
76 | setup_file_and_group_paths(options[:module_path], options[:module_path], PATH_TYPE_PROJECT)
77 | setup_file_and_group_paths(options[:test_path], options[:test_path], PATH_TYPE_TEST)
78 |
79 | @podfile_path = rambafile[PODFILE_PATH_KEY] if rambafile[PODFILE_PATH_KEY]
80 | @cartfile_path = rambafile[CARTFILE_PATH_KEY] if rambafile[CARTFILE_PATH_KEY]
81 | end
82 |
83 | private
84 |
85 | def setup_file_and_group_paths(file_path, group_path, path_type)
86 | if file_path || group_path
87 | variable_name = "#{path_type}_file_path"
88 |
89 | if file_path || !instance_variable_get("@#{variable_name}")
90 | file_path = group_path unless file_path
91 |
92 | variable_value = file_path.gsub(SLASH_REGEX, '')
93 | variable_value = Pathname.new(variable_value).join(@name)
94 | instance_variable_set("@#{variable_name}", variable_value)
95 | end
96 |
97 | variable_name = "#{path_type}_group_path"
98 |
99 | if group_path || !instance_variable_get("@#{variable_name}")
100 | group_path = file_path unless group_path
101 |
102 | variable_value = group_path.gsub(SLASH_REGEX, '')
103 | variable_value = Pathname.new(variable_value).join(@name)
104 | instance_variable_set("@#{variable_name}", variable_value)
105 | end
106 | end
107 | end
108 | end
109 | end
110 |
--------------------------------------------------------------------------------
/lib/generamba/code_generation/content_generator.rb:
--------------------------------------------------------------------------------
1 | require 'liquid'
2 |
3 | module Generamba
4 |
5 | # Responsible for generating code using provided liquid templates
6 | class ContentGenerator
7 |
8 | # Generates and returns a filename and a body of a specific code file.
9 | # @param file [Hash] A hashmap with template's filename and filepath
10 | # @param scope [Hash] A hashmap with module info
11 | # @param template [ModuleTemplate] The model describing a Generamba template used for code generation
12 | #
13 | # @return [String], [String] The generated file_name and body
14 | def self.create_file(file, scope, template)
15 | file_source = IO.read(template.template_path.join(file[TEMPLATE_FILE_PATH_KEY]))
16 | Liquid::Template.file_system = Liquid::LocalFileSystem.new(template.template_path.join('snippets'), '%s.liquid')
17 |
18 | template = Liquid::Template.parse(file_source)
19 | filename_template = self.file_name_template(file)
20 |
21 | file_basename = File.basename(file[TEMPLATE_FILE_NAME_KEY])
22 |
23 | module_info = scope['module_info']
24 |
25 | module_info['file_basename'] = file_basename
26 |
27 | file_name = filename_template.render(scope)
28 |
29 | module_info['file_name'] = file_name
30 | module_info.delete('file_basename')
31 |
32 | content = template.render(scope)
33 |
34 | return file_name, content
35 | end
36 |
37 | def self.file_name_template(file)
38 | template_default_text = '{{ prefix }}{{ module_info.name }}{{ module_info.file_basename }}'
39 | template_text = file[TEMPLATE_FILE_CUSTOM_NAME_KEY] || template_default_text
40 | return Liquid::Template.parse(template_text)
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/lib/generamba/code_generation/module_template.rb:
--------------------------------------------------------------------------------
1 | require 'generamba/helpers/template_helper.rb'
2 |
3 | module Generamba
4 |
5 | # Represents a single Generamba module template
6 | class ModuleTemplate
7 | attr_reader :template_name, :template_path, :code_files, :test_files, :dependencies
8 |
9 | def initialize(name, options = nil)
10 | spec_path = TemplateHelper.obtain_spec(name)
11 |
12 | unless options
13 | spec = YAML.load_file(spec_path)
14 | else
15 | spec_source = IO.read(spec_path)
16 | spec_template = Liquid::Template.parse(spec_source)
17 | spec_content = spec_template.render(options)
18 | spec = YAML.load(spec_content)
19 | end
20 |
21 | @code_files = spec[TEMPLATE_CODE_FILES_KEY]
22 | @test_files = spec[TEMPLATE_TEST_FILES_KEY]
23 | @template_name = spec[TEMPLATE_NAME_KEY]
24 | @template_path = TemplateHelper.obtain_path(name)
25 | @dependencies = spec[TEMPLATE_DEPENDENCIES_KEY]
26 | end
27 | end
28 | end
--------------------------------------------------------------------------------
/lib/generamba/code_generation/rambafile_generator.rb:
--------------------------------------------------------------------------------
1 | require 'liquid'
2 |
3 | module Generamba
4 |
5 | # Responsible for creating Generamba configs
6 | class RambafileGenerator
7 |
8 | # Creates a Rambafile using the provided properties hashmap
9 | # @param properties Rambafile properties
10 | #
11 | # @return void
12 | def self.create_rambafile(properties)
13 | file_source = IO.read(File.dirname(__FILE__) + '/Rambafile.liquid')
14 |
15 | template = Liquid::Template.parse(file_source)
16 | output = template.render(properties).gsub!(/[\n]{3,}/, "\n\n");
17 |
18 | File.open(RAMBAFILE_NAME, 'w+') {|f|
19 | f.write(output)
20 | }
21 | end
22 | end
23 | end
--------------------------------------------------------------------------------
/lib/generamba/configuration/user_preferences.rb:
--------------------------------------------------------------------------------
1 | require 'generamba/constants/user_preferences_constants.rb'
2 |
3 | module Generamba
4 |
5 | # A class that provides methods for working with user-specific information.
6 | # Currently it has methods for obtaining and saving username, later it may be improved to something more general.
7 | class UserPreferences
8 |
9 | def self.obtain_username
10 | path = obtain_user_preferences_path
11 |
12 | file_contents = open(path).read
13 | preferences = file_contents.empty? ? {} : YAML.load(file_contents).to_hash
14 |
15 | return preferences[USERNAME_KEY]
16 | end
17 |
18 | def self.save_username(username)
19 | path = obtain_user_preferences_path
20 |
21 | file_contents = open(path).read
22 | preferences = file_contents.empty? ? {} : YAML.load(file_contents).to_hash
23 |
24 | preferences[USERNAME_KEY] = username
25 | File.open(path, 'w+') { |f| f.write(preferences.to_yaml) }
26 | end
27 |
28 | private
29 |
30 | def self.obtain_user_preferences_path
31 | home_path = Pathname.new(ENV['HOME'])
32 | .join(GENERAMBA_HOME_DIR)
33 |
34 | path_exists = Dir.exist?(home_path)
35 |
36 | unless path_exists
37 | FileUtils.mkdir_p home_path
38 | end
39 |
40 | preferences_path = home_path.join(USER_PREFERENCES_FILE)
41 | preferences_exist = File.file?(preferences_path)
42 |
43 | unless preferences_exist
44 | File.open(preferences_path, 'w+') { |f| f.write('') }
45 | end
46 |
47 | return preferences_path
48 | end
49 | end
50 | end
--------------------------------------------------------------------------------
/lib/generamba/constants/constants.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 |
3 | # General constants
4 | RAMBAFILE_NAME = 'Rambafile'
5 | RAMBASPEC_EXTENSION = '.rambaspec'
6 | TEMPLATES_FOLDER = 'Templates'
7 | RAMBLER_CATALOG_REPO = 'https://github.com/rambler-digital-solutions/generamba-catalog'
8 | GENERAMBA_CATALOG_NAME = 'generamba-catalog'
9 | GENERAMBA_HOME_DIR = '.generamba'
10 | CATALOGS_DIR = 'catalogs'
11 | USER_PREFERENCES_FILE = 'user_preferences.yml'
12 | end
--------------------------------------------------------------------------------
/lib/generamba/constants/rambafile_constants.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 |
3 | # Keys of Rambafile files
4 | COMPANY_KEY = 'company'
5 | AUTHOR_NAME_KEY = 'author'
6 | PROJECT_NAME_KEY = 'project_name'
7 | PROJECT_PREFIX_KEY = 'prefix'
8 | XCODEPROJ_PATH_KEY = 'xcodeproj_path'
9 |
10 | PROJECT_TARGET_KEY = 'project_target'
11 | PROJECT_TARGETS_KEY = 'project_targets'
12 | PROJECT_FILE_PATH_KEY = 'project_file_path'
13 | PROJECT_GROUP_PATH_KEY = 'project_group_path'
14 |
15 | PRODUCT_MODULE_NAME_KEY = 'product_module_name'
16 |
17 | TEST_TARGET_KEY = 'test_target'
18 | TEST_TARGETS_KEY = 'test_targets'
19 | TEST_FILE_PATH_KEY = 'test_file_path'
20 | TEST_GROUP_PATH_KEY = 'test_group_path'
21 |
22 | PODFILE_PATH_KEY = 'podfile_path'
23 | CARTFILE_PATH_KEY = 'cartfile_path'
24 |
25 | CREATE_LOGICAL_GROUPS_KEY = 'create_logical_groups'
26 |
27 | CATALOGS_KEY = 'catalogs'
28 | TEMPLATES_KEY = 'templates'
29 | TEMPLATE_DECLARATION_NAME_KEY = 'name'
30 | TEMPLATE_DECLARATION_LOCAL_KEY = 'local'
31 | TEMPLATE_DECLARATION_GIT_KEY = 'git'
32 | TEMPLATE_DECLARATION_BRANCH_KEY = 'branch'
33 | end
34 |
--------------------------------------------------------------------------------
/lib/generamba/constants/rambaspec_constants.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 |
3 | # Keys of .rambaspec files
4 | TEMPLATE_NAME_KEY = 'name'
5 | TEMPLATE_SUMMARY_KEY = 'summary'
6 | TEMPLATE_AUTHOR_KEY = 'author'
7 | TEMPLATE_VERSION_KEY = 'version'
8 | TEMPLATE_LICENSE_KEY = 'license'
9 |
10 | TEMPLATE_CODE_FILES_KEY = 'code_files'
11 | TEMPLATE_TEST_FILES_KEY = 'test_files'
12 | TEMPLATE_FILE_NAME_KEY = 'name'
13 | TEMPLATE_FILE_CUSTOM_NAME_KEY = 'custom_name'
14 | TEMPLATE_FILE_PATH_KEY = 'path'
15 | TEMPLATE_FILE_IS_RESOURCE_KEY = 'is_resource'
16 |
17 | TEMPLATE_DEPENDENCIES_KEY = 'dependencies'
18 | end
--------------------------------------------------------------------------------
/lib/generamba/constants/user_preferences_constants.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 |
3 | # Keys of file user_preferences.yml
4 | USERNAME_KEY = 'username'
5 | end
--------------------------------------------------------------------------------
/lib/generamba/helpers/dependency_checker.rb:
--------------------------------------------------------------------------------
1 | require 'cocoapods-core'
2 |
3 | module Generamba
4 | # Provides methods for check dependencies from rambaspec in podfile
5 | class DependencyChecker
6 | # Check Podfile for dependencies
7 | # @param dependencies [Array] Array of dependencies name
8 | # @param podfile_path [String] String of Podfile path
9 | #
10 | # @return [void]
11 | def self.check_all_required_dependencies_has_in_podfile(dependencies, podfile_path)
12 | return if !dependencies || dependencies.count == 0 || !podfile_path
13 |
14 | dependencies_names = []
15 | Pod::Podfile.from_file(Pathname.new(podfile_path)).dependencies.each do |dependency|
16 | dependencies_names.push(dependency.name.gsub(/ .*/, ''))
17 | end
18 |
19 | not_existing_dependency = []
20 |
21 | dependencies.each do |dependency_name|
22 | unless dependencies_names.include?(dependency_name)
23 | not_existing_dependency.push(dependency_name)
24 | end
25 | end
26 |
27 | if not_existing_dependency.count > 0
28 | puts "[Warning] Dependencies #{not_existing_dependency} missed in Podfile".yellow
29 | end
30 | end
31 |
32 | # Check Cartfile for dependencies
33 | # @param dependencies [Array] Array of dependencies name
34 | # @param cartfile_path [String] String of Podfile path
35 | #
36 | # @return [void]
37 | def self.check_all_required_dependencies_has_in_cartfile(dependencies, cartfile_path)
38 | return if !dependencies || dependencies.count == 0 || !cartfile_path
39 |
40 | cartfile_string = File.read(cartfile_path)
41 |
42 | not_existing_dependency = []
43 | dependencies.each do |dependency_name|
44 | unless cartfile_string.include?(dependency_name)
45 | not_existing_dependency.push(dependency_name)
46 | end
47 | end
48 |
49 | if not_existing_dependency.count > 0
50 | puts "[Warning] Dependencies #{not_existing_dependency} missed in Cartfile".yellow
51 | end
52 | end
53 | end
54 | end
55 |
--------------------------------------------------------------------------------
/lib/generamba/helpers/gen_command_table_parameters_formatter.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 | # Provides methods for prepare parameters for displaying in table.
3 | class GenCommandTableParametersFormatter
4 | require 'json'
5 |
6 | # This method prepared parameter for displaying
7 | def self.prepare_parameters_for_displaying(code_module, template_name)
8 | params = {}
9 |
10 | params['Targets'] = code_module.project_targets.join(',') if code_module.project_targets
11 | params['Module path'] = code_module.project_file_path if code_module.project_file_path
12 |
13 | if code_module.project_file_path != code_module.project_group_path
14 | params['Module group path'] = code_module.project_group_path
15 | end
16 |
17 | params['Test targets'] = code_module.test_targets.join(',') if code_module.test_targets
18 | params['Test file path'] = code_module.test_file_path if code_module.test_file_path
19 |
20 | if code_module.test_file_path != code_module.test_group_path
21 | params['Test group path'] = code_module.test_group_path
22 | end
23 |
24 | params['Template'] = template_name
25 |
26 | unless code_module.custom_parameters.empty?
27 | params['Custom parameters'] = code_module.custom_parameters.to_json
28 | end
29 |
30 | params
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/lib/generamba/helpers/module_info_generator.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 |
3 | class ModuleInfoGenerator
4 | attr_reader :scope
5 |
6 | def initialize(code_module)
7 | module_info = {
8 | 'name' => code_module.name,
9 | 'description' => code_module.description,
10 | 'project_name' => code_module.project_name,
11 | 'product_module_name' => code_module.product_module_name,
12 | 'project_targets' => code_module.project_targets,
13 | 'test_targets' => code_module.test_targets
14 | }
15 |
16 | developer = {
17 | 'name' => code_module.author,
18 | 'company' => code_module.company
19 | }
20 |
21 | @scope = {
22 | 'year' => code_module.year,
23 | 'date' => Time.now.strftime('%d/%m/%Y'),
24 | 'developer' => developer,
25 | 'module_info' => module_info,
26 | 'prefix' => code_module.prefix,
27 | 'custom_parameters' => code_module.custom_parameters
28 | }
29 | end
30 |
31 | end
32 |
33 | end
--------------------------------------------------------------------------------
/lib/generamba/helpers/module_validator.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 | # Provides methods for validating module
3 | class ModuleValidator
4 |
5 | TARGET_TYPE_PROJECT = 'project'
6 | TARGET_TYPE_TEST = 'test'
7 |
8 | # Method validates module
9 | # @param code_module [CodeModule] The instance of CodeModule
10 | #
11 | # @return [Void]
12 | def validate(code_module)
13 | mandatory_fields = [COMPANY_KEY,
14 | PROJECT_NAME_KEY,
15 | XCODEPROJ_PATH_KEY]
16 |
17 | mandatory_fields.each do |field|
18 | unless code_module.instance_variable_get("@#{field}")
19 | puts "Module is broken! *#{field}* field cannot be empty, because it is mandatory.".red
20 | exit
21 | end
22 | end
23 |
24 | project_failure_fields = all_project_failure_fields(code_module)
25 | test_failure_fields = all_test_failure_fields(code_module)
26 | failure_fields = project_failure_fields + test_failure_fields
27 |
28 | if failure_fields.count > 0
29 | puts "Module is broken! *#{failure_fields}* field cannot be empty, because it is mandatory.".red
30 | exit
31 | end
32 | end
33 |
34 | private
35 |
36 | # Method which return all project failure fields
37 | # @param code_module [CodeModule] The instance of CodeModule
38 | #
39 | # @return [Array]
40 | def all_project_failure_fields(code_module)
41 | return [] if !code_module.project_targets && !code_module.project_file_path && !code_module.project_group_path
42 |
43 | all_nil_mandatory_fields_for_target_type(TARGET_TYPE_PROJECT, code_module)
44 | end
45 |
46 | # Method which return all test failure fields
47 | # @param code_module [CodeModule] The instance of CodeModule
48 | #
49 | # @return [Array]
50 | def all_test_failure_fields(code_module)
51 | return [] if !code_module.test_targets && !code_module.test_file_path && !code_module.test_group_path
52 |
53 | all_nil_mandatory_fields_for_target_type(TARGET_TYPE_TEST, code_module)
54 | end
55 |
56 | # Method which return all failure fields for target_type
57 | # @param target_type [String] "project" or "test"
58 | # @param code_module [CodeModule] The instance of CodeModule
59 | #
60 | # @return [Array]
61 | def all_nil_mandatory_fields_for_target_type(target_type, code_module)
62 | fields = []
63 |
64 | variable_name = "#{target_type}_targets"
65 |
66 | unless code_module.instance_variable_get("@#{variable_name}")
67 | target_const_value = Generamba.const_get(target_type.upcase + '_TARGET_KEY')
68 | targets_const_value = Generamba.const_get(target_type.upcase + '_TARGETS_KEY')
69 | fields.push(target_const_value)
70 | fields.push(targets_const_value)
71 | end
72 |
73 | variable_name = "#{target_type}_file_path"
74 | file_path_const_value = Generamba.const_get(target_type.upcase + '_FILE_PATH_KEY')
75 | fields.push(file_path_const_value) unless code_module.instance_variable_get("@#{variable_name}")
76 |
77 | variable_name = "#{target_type}_group_path"
78 | group_path_const_value = Generamba.const_get(target_type.upcase + '_GROUP_PATH_KEY')
79 | fields.push(group_path_const_value) unless code_module.instance_variable_get("@#{variable_name}")
80 |
81 | fields
82 | end
83 |
84 | end
85 | end
--------------------------------------------------------------------------------
/lib/generamba/helpers/print_table.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 | # Provides methods for print parameters in nice table.
3 | class PrintTable
4 | # This method prints out all the user inputs in a nice table.
5 | def self.print_values(values: nil, title: nil)
6 | require 'terminal-table'
7 |
8 | params = {}
9 | params[:rows] = values
10 | params[:title] = title.green if title
11 |
12 | puts ''
13 | puts Terminal::Table.new(params)
14 | puts ''
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/generamba/helpers/rambafile_validator.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 | # Provides methods for validating Rambafile contents
3 | class RambafileValidator
4 | # Method validates Rambafile contents
5 | # @param path [String] The path to a Rambafile
6 | #
7 | # @return [Void]
8 | def validate(path)
9 | file_contents = open(path).read
10 | preferences = file_contents.empty? ? {} : YAML.load(file_contents).to_hash
11 |
12 | unless preferences[TEMPLATES_KEY]
13 | puts "You can't run *generamba gen* without any templates installed. Add their declarations to a Rambafile and run *generamba template install*.".red
14 | exit
15 | end
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/generamba/helpers/template_helper.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 | # Provides a number of helper methods for manipulating Generamba template files
3 | class TemplateHelper
4 | # Returns a file path for a specific template .rambaspec file
5 | # @param template_name [String] The Generamba template name
6 | #
7 | # @return [Pathname]
8 | def self.obtain_spec(template_name)
9 | template_path = self.obtain_path(template_name)
10 | spec_path = template_path.join(template_name + RAMBASPEC_EXTENSION)
11 |
12 | spec_path
13 | end
14 |
15 | # Returns a file path for a specific template folder
16 | # @param template_name [String] The Generamba template name
17 | #
18 | # @return [Pathname]
19 | def self.obtain_path(template_name)
20 | path = Pathname.new(Dir.getwd)
21 | .join(TEMPLATES_FOLDER)
22 | .join(template_name)
23 |
24 | error_description = "Cannot find template named #{template_name}! Add it to the Rambafile and run *generamba template install*".red
25 | raise StandardError, error_description unless path.exist?
26 |
27 | path
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/lib/generamba/helpers/xcodeproj_helper.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 | # Provides a number of helper methods for working with xcodeproj gem
3 | class XcodeprojHelper
4 | # Returns a PBXProject class for a given name
5 | # @param project_name [String] The name of the project file
6 | #
7 | # @return [Xcodeproj::Project]
8 | def self.obtain_project(project_name)
9 | Xcodeproj::Project.open(project_name)
10 | end
11 |
12 | # Adds a provided file to a specific Project and Target
13 | # @param project [Xcodeproj::Project] The target xcodeproj file
14 | # @param targets_name [String] Array of targets name
15 | # @param group_path [Pathname] The Xcode group path for current file
16 | # @param dir_path [Pathname] The directory path for current file
17 | # @param file_group_path [String] Directory path
18 | # @param file_name [String] Current file name
19 | # @param file_is_resource [TrueClass or FalseClass] If true then file is resource
20 | #
21 | # @return [void]
22 | def self.add_file_to_project_and_targets(project, targets_name, group_path, dir_path, file_group_path, file_name, root_path, file_is_resource = false)
23 |
24 | if root_path
25 | file_path = root_path
26 | else
27 | file_path = dir_path
28 | file_path = file_path.join(file_group_path) if file_group_path
29 | end
30 |
31 | file_path = file_path.join(file_name) if file_name
32 |
33 | module_group = self.retrieve_group_or_create_if_needed(group_path, dir_path, file_group_path, project, true, root_path)
34 | xcode_file = module_group.new_file(File.absolute_path(file_path))
35 |
36 | targets_name.each do |target|
37 | xcode_target = obtain_target(target, project)
38 |
39 | if file_is_resource || self.is_bundle_resource?(file_name)
40 | xcode_target.add_resources([xcode_file])
41 | elsif self.is_compile_source?(file_name)
42 | xcode_target.add_file_references([xcode_file])
43 | end
44 | end
45 | end
46 |
47 | # Adds a provided directory to a specific Project
48 | # @param project [Xcodeproj::Project] The target xcodeproj file
49 | # @param group_path [Pathname] The Xcode group path for current directory
50 | # @param dir_path [Pathname] The directory path for current directory
51 | # @param directory_name [String] Current directory name
52 | #
53 | # @return [void]
54 | def self.add_group_to_project(project, group_path, dir_path, directory_name, group_is_logical)
55 | self.retrieve_group_or_create_if_needed(group_path, dir_path, directory_name, project, true, group_is_logical)
56 | end
57 |
58 | # File is a compiled source
59 | # @param file_name [String] String of file name
60 | #
61 | # @return [TrueClass or FalseClass]
62 | def self.is_compile_source?(file_name)
63 | File.extname(file_name) == '.m' || File.extname(file_name) == '.swift' || File.extname(file_name) == '.mm'
64 | end
65 |
66 | # File is a resource
67 | # @param resource_name [String] String of resource name
68 | #
69 | # @return [TrueClass or FalseClass]
70 | def self.is_bundle_resource?(resource_name)
71 | File.extname(resource_name) == '.xib' || File.extname(resource_name) == '.storyboard'
72 | end
73 |
74 | # Recursively clears children of the given group
75 | # @param project [Xcodeproj::Project] The working Xcode project file
76 | # @param group_path [Pathname] The full group path
77 | #
78 | # @return [Void]
79 | def self.clear_group(project, targets_name, group_path, group_is_logical)
80 | module_group = self.retrieve_group_or_create_if_needed(group_path, nil, nil, project, false, group_is_logical)
81 | return unless module_group
82 |
83 | files_path = self.files_path_from_group(module_group, project)
84 | return unless files_path
85 |
86 | files_path.each do |file_path|
87 | self.remove_file_by_file_path(file_path, targets_name, project)
88 | end
89 |
90 | module_group.clear
91 | end
92 |
93 | # Finds a group in a xcodeproj file with a given path
94 | # @param project [Xcodeproj::Project] The working Xcode project file
95 | # @param group_path [Pathname] The full group path
96 | #
97 | # @return [TrueClass or FalseClass]
98 | def self.module_with_group_path_already_exists(project, group_path, group_is_logical)
99 | module_group = self.retrieve_group_or_create_if_needed(group_path, nil, nil, project, false, group_is_logical)
100 | module_group.nil? ? false : true
101 | end
102 |
103 | private
104 |
105 | # Finds or creates a group in a xcodeproj file with a given path
106 | # @param group_path [Pathname] The Xcode group path for module
107 | # @param dir_path [Pathname] The directory path for module
108 | # @param file_group_path [String] Directory path
109 | # @param project [Xcodeproj::Project] The working Xcode project file
110 | # @param create_group_if_not_exists [TrueClass or FalseClass] If true nonexistent group will be created
111 | #
112 | # @return [PBXGroup]
113 | def self.retrieve_group_or_create_if_needed(group_path, dir_path, file_group_path, project, create_group_if_not_exists, group_is_logical = false)
114 | group_names = path_names_from_path(group_path)
115 | group_components_count = group_names.count
116 | group_names += path_names_from_path(file_group_path) if file_group_path
117 |
118 | final_group = project
119 |
120 | group_names.each_with_index do |group_name, index|
121 | next_group = final_group[group_name]
122 |
123 | unless next_group
124 | return nil unless create_group_if_not_exists
125 |
126 | if group_path != dir_path && index == group_components_count-1
127 | next_group = group_is_logical ? final_group.new_group(group_name) : final_group.new_group(group_name, dir_path, :project)
128 | else
129 | next_group = group_is_logical ? final_group.new_group(group_name) : final_group.new_group(group_name, group_name)
130 | end
131 | end
132 |
133 | final_group = next_group
134 | end
135 |
136 | final_group
137 | end
138 |
139 | # Returns an AbstractTarget class for a given name
140 | # @param target_name [String] The name of the target
141 | # @param project [Xcodeproj::Project] The target xcodeproj file
142 | #
143 | # @return [Xcodeproj::AbstractTarget]
144 | def self.obtain_target(target_name, project)
145 | project.targets.each do |target|
146 | return target if target.name == target_name
147 | end
148 |
149 | error_description = "Cannot find a target with name #{target_name} in Xcode project".red
150 | raise StandardError, error_description
151 | end
152 |
153 | # Splits the provided Xcode path to an array of separate paths
154 | # @param path The full group or file path
155 | #
156 | # @return [[String]]
157 | def self.path_names_from_path(path)
158 | path.to_s.split('/')
159 | end
160 |
161 | # Remove build file from target build phase
162 | # @param file_path [String] The path of the file
163 | # @param targets_name [String] Array of targets
164 | # @param project [Xcodeproj::Project] The target xcodeproj file
165 | #
166 | # @return [Void]
167 | def self.remove_file_by_file_path(file_path, targets_name, project)
168 | file_names = path_names_from_path(file_path)
169 |
170 | build_phases = nil
171 |
172 | if self.is_compile_source?(file_names.last)
173 | build_phases = self.build_phases_from_targets(targets_name, project)
174 | elsif self.is_bundle_resource?(file_names.last)
175 | build_phases = self.resources_build_phase_from_targets(targets_name, project)
176 | end
177 |
178 | self.remove_file_from_build_phases(file_path, build_phases)
179 | end
180 |
181 | def self.remove_file_from_build_phases(file_path, build_phases)
182 | return if build_phases.nil?
183 |
184 | build_phases.each do |build_phase|
185 | build_phase.files.each do |build_file|
186 | next if build_file.nil? || build_file.file_ref.nil?
187 |
188 | build_file_path = self.configure_file_ref_path(build_file.file_ref)
189 |
190 | if build_file_path == file_path
191 | build_phase.remove_build_file(build_file)
192 | end
193 | end
194 | end
195 | end
196 |
197 | # Find and return target build phases
198 | # @param targets_name [String] Array of targets
199 | # @param project [Xcodeproj::Project] The target xcodeproj file
200 | #
201 | # @return [[PBXSourcesBuildPhase]]
202 | def self.build_phases_from_targets(targets_name, project)
203 | build_phases = []
204 |
205 | targets_name.each do |target_name|
206 | xcode_target = self.obtain_target(target_name, project)
207 | xcode_target.build_phases.each do |build_phase|
208 | if build_phase.isa == 'PBXSourcesBuildPhase'
209 | build_phases.push(build_phase)
210 | end
211 | end
212 | end
213 |
214 | build_phases
215 | end
216 |
217 | # Find and return target resources build phase
218 | # @param targets_name [String] Array of targets
219 | # @param project [Xcodeproj::Project] The target xcodeproj file
220 | #
221 | # @return [[PBXResourcesBuildPhase]]
222 | def self.resources_build_phase_from_targets(targets_name, project)
223 | resource_build_phase = []
224 |
225 | targets_name.each do |target_name|
226 | xcode_target = self.obtain_target(target_name, project)
227 | resource_build_phase.push(xcode_target.resources_build_phase)
228 | end
229 |
230 | resource_build_phase
231 | end
232 |
233 | # Get configure file full path
234 | # @param file_ref [PBXFileReference] Build file
235 | #
236 | # @return [String]
237 | def self.configure_file_ref_path(file_ref)
238 | build_file_ref_path = file_ref.hierarchy_path.to_s
239 | build_file_ref_path[0] = ''
240 |
241 | build_file_ref_path
242 | end
243 |
244 | # Get all files path from group path
245 | # @param module_group [PBXGroup] The module group
246 | # @param project [Xcodeproj::Project] The target xcodeproj file
247 | #
248 | # @return [[String]]
249 | def self.files_path_from_group(module_group, _project)
250 | files_path = []
251 |
252 | module_group.recursive_children.each do |file_ref|
253 | if file_ref.isa == 'PBXFileReference'
254 | file_ref_path = configure_file_ref_path(file_ref)
255 | files_path.push(file_ref_path)
256 | end
257 | end
258 |
259 | files_path
260 | end
261 | end
262 | end
263 |
--------------------------------------------------------------------------------
/lib/generamba/module_generator.rb:
--------------------------------------------------------------------------------
1 | require 'fileutils'
2 |
3 | require 'generamba/helpers/xcodeproj_helper.rb'
4 | require 'generamba/helpers/module_info_generator.rb'
5 |
6 | module Generamba
7 |
8 | # Responsible for creating the whole code module using information from the CLI
9 | class ModuleGenerator
10 |
11 | def generate_module(name, code_module, template)
12 | # Setting up Xcode objects
13 | project = XcodeprojHelper.obtain_project(code_module.xcodeproj_path)
14 |
15 | # Configuring file paths
16 | if code_module.project_file_root && code_module.test_file_root
17 | FileUtils.mkdir_p code_module.project_file_root if code_module.project_file_root
18 | FileUtils.mkdir_p code_module.test_file_root if code_module.test_file_root
19 | else
20 | FileUtils.mkdir_p code_module.project_file_path if code_module.project_file_path
21 | FileUtils.mkdir_p code_module.test_file_path if code_module.test_file_path
22 | end
23 |
24 | # Creating code files
25 | if code_module.project_targets && code_module.project_group_path && code_module.project_file_path
26 | puts('Creating code files...')
27 | process_files_if_needed(template.code_files,
28 | code_module,
29 | template,
30 | project,
31 | code_module.project_targets,
32 | code_module.project_group_path,
33 | code_module.project_file_path,
34 | code_module.project_file_root)
35 | end
36 |
37 |
38 | # Creating test files
39 | if code_module.test_targets && code_module.test_group_path && code_module.test_file_path
40 | puts('Creating test files...')
41 | process_files_if_needed(template.test_files,
42 | code_module,
43 | template,
44 | project,
45 | code_module.test_targets,
46 | code_module.test_group_path,
47 | code_module.test_file_path,
48 | code_module.test_file_root,
49 | [code_module.project_group_path])
50 | end
51 |
52 | # Saving the current changes in the Xcode project
53 | project.save
54 |
55 | puts 'Module successfully created!'
56 | puts "Name: #{name}".green
57 | puts "Project file path: #{code_module.project_file_path}".green if code_module.project_file_path
58 | puts "Project group path: #{code_module.project_group_path}".green if code_module.project_group_path
59 | puts "Test file path: #{code_module.test_file_path}".green if code_module.test_file_path
60 | puts "Test group path: #{code_module.test_group_path}".green if code_module.test_group_path
61 | end
62 |
63 | def process_files_if_needed(files, code_module, template, project, targets, group_path, dir_path, root_path, processed_groups = [])
64 | # It's possible that current project doesn't test targets configured, so it doesn't need to generate tests.
65 | # The same is for files property - a template can have only test or project files
66 | if targets.count == 0 || files == nil || files.count == 0 || dir_path == nil || group_path == nil
67 | return
68 | end
69 |
70 | XcodeprojHelper.clear_group(project, targets, group_path, code_module.create_logical_groups) unless processed_groups.include? group_path
71 | files.each do |file|
72 | unless file[TEMPLATE_FILE_PATH_KEY]
73 | directory_name = file[TEMPLATE_NAME_KEY].gsub(/^\/|\/$/, '')
74 | file_group = dir_path.join(directory_name)
75 |
76 | FileUtils.mkdir_p root_path
77 | XcodeprojHelper.add_group_to_project(project, group_path, dir_path, directory_name, code_module.create_logical_groups)
78 |
79 | next
80 | end
81 |
82 | file_group = File.dirname(file[TEMPLATE_NAME_KEY])
83 | file_group = nil if file_group == '.'
84 |
85 | module_info = ModuleInfoGenerator.new(code_module)
86 |
87 | # Generating the content of the code file and it's name
88 | file_name, file_content = ContentGenerator.create_file(file, module_info.scope, template)
89 | if code_module.create_logical_groups
90 | file_path = root_path
91 | else
92 | file_path = dir_path
93 | file_path = file_path.join(file_group) if file_group
94 | end
95 |
96 | file_path = file_path.join(file_name) if file_name
97 |
98 | # Creating the file in the filesystem
99 | FileUtils.mkdir_p File.dirname(file_path) if !code_module.create_logical_groups
100 | File.open(file_path, 'w+') do |f|
101 | f.write(file_content)
102 | end
103 |
104 | file_is_resource = file[TEMPLATE_FILE_IS_RESOURCE_KEY]
105 |
106 | # Creating the file in the Xcode project
107 | XcodeprojHelper.add_file_to_project_and_targets(project,
108 | targets,
109 | group_path,
110 | dir_path,
111 | file_group,
112 | file_name,
113 | root_path,
114 | file_is_resource)
115 | end
116 | end
117 | end
118 | end
119 |
--------------------------------------------------------------------------------
/lib/generamba/template/creator/new_template/Code/Service/service.h.liquid:
--------------------------------------------------------------------------------
1 | //
2 | // {{ prefix }}{{ module_info.name }}{{ module_info.file_name }}
3 | // {{ module_info.project_name }}
4 | //
5 | // Created by {{ developer.name }} on {{ date }}.
6 | // Copyright {{ year }} {{ developer.company }}. All rights reserved.
7 | //
8 |
9 | @interface {{ prefix }}{{ module_info.name }}Service : NSObject
10 |
11 | @end
--------------------------------------------------------------------------------
/lib/generamba/template/creator/new_template/Code/Service/service.m.liquid:
--------------------------------------------------------------------------------
1 | //
2 | // {{ prefix }}{{ module_info.name }}{{ module_info.file_name }}
3 | // {{ module_info.project_name }}
4 | //
5 | // Created by {{ developer.name }} on {{ date }}.
6 | // Copyright {{ year }} {{ developer.company }}. All rights reserved.
7 | //
8 |
9 | #import "{{ prefix }}{{ module_info.name }}Service.h"
10 |
11 | @implementation {{ prefix }}{{ module_info.name }}Service
12 |
13 | @end
--------------------------------------------------------------------------------
/lib/generamba/template/creator/new_template/Tests/Service/service_tests.m.liquid:
--------------------------------------------------------------------------------
1 | //
2 | // {{ prefix }}{{ module_info.name }}{{ module_info.file_name }}
3 | // {{ module_info.project_name }}
4 | //
5 | // Created by {{ developer.name }} on {{ date }}.
6 | // Copyright {{ year }} {{ developer.company }}. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "{{ prefix }}{{ module_info.name }}Service.h"
12 |
13 | @interface {{ prefix }}{{ module_info.name }}ServiceTests : XCTestCase
14 |
15 | @property (strong, nonatomic) {{ prefix }}{{ module_info.name }}Service *service;
16 |
17 | @end
18 |
19 | @implementation {{ prefix }}{{ module_info.name }}ServiceTests
20 |
21 | #pragma mark - Test environment setup
22 |
23 | - (void)setUp {
24 | [super setUp];
25 |
26 | self.service = [[{{ prefix }}{{ module_info.name }}Service alloc] init];
27 | }
28 |
29 | - (void)tearDown {
30 | self.service = nil;
31 |
32 | [super tearDown];
33 | }
34 |
35 | @end
--------------------------------------------------------------------------------
/lib/generamba/template/creator/new_template/template.rambaspec.liquid:
--------------------------------------------------------------------------------
1 | # Template information section
2 | name: {{ name }}
3 | summary: {{ summary }}
4 | author: {{ author }}
5 | version: 1.0.0
6 | license: {{ license }}
7 |
8 | # The declarations for code files
9 | code_files:
10 | - {name: Service/Service.h, path: Code/Service/service.h.liquid}
11 | - {name: Service/Service.m, path: Code/Service/service.m.liquid}
12 |
13 | # The declarations for test files
14 | test_files:
15 | - {name: Service/ServiceTests.m, path: Tests/Service/service_tests.m.liquid}
16 |
17 | # Template dependencies
18 | dependencies:
19 | {% for dependency in dependencies %}- {{ dependency }}
20 | {% endfor %}
--------------------------------------------------------------------------------
/lib/generamba/template/creator/template_creator.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 |
3 | # Responsible for generating new .rambaspec files
4 | class TemplateCreator
5 |
6 | NEW_TEMPLATE_FOLDER = 'new_template'
7 | RAMBASPEC_TEMPLATE_NAME = 'template.rambaspec.liquid'
8 | CODE_FOLDER = 'Code'
9 | TESTS_FOLDER = 'Tests'
10 |
11 | # Generates and saves to filesystem a new template with a .rambaspec file and sample code and tests files
12 | # @param properties [Hash] User-inputted template properties
13 | #
14 | # @return [Void]
15 | def create_template(properties)
16 | template_dir_path = Pathname.new(File.dirname(__FILE__)).join(NEW_TEMPLATE_FOLDER)
17 | rambaspec_template_file_path = template_dir_path.join(RAMBASPEC_TEMPLATE_NAME)
18 | code_file_path = template_dir_path.join(CODE_FOLDER)
19 | tests_file_path = template_dir_path.join(TESTS_FOLDER)
20 |
21 | file_source = IO.read(rambaspec_template_file_path)
22 |
23 | template = Liquid::Template.parse(file_source)
24 | output = template.render(properties)
25 |
26 | result_name = properties[TEMPLATE_NAME_KEY] + RAMBASPEC_EXTENSION
27 | result_dir_path = Pathname.new(properties[TEMPLATE_NAME_KEY])
28 |
29 | FileUtils.mkdir_p result_dir_path
30 | FileUtils.cp_r(code_file_path, result_dir_path)
31 | FileUtils.cp_r(tests_file_path, result_dir_path)
32 |
33 | File.open(result_dir_path.join(result_name), 'w+') {|f|
34 | f.write(output)
35 | }
36 | end
37 |
38 | end
39 | end
--------------------------------------------------------------------------------
/lib/generamba/template/helpers/catalog_downloader.rb:
--------------------------------------------------------------------------------
1 | require 'git'
2 |
3 | module Generamba
4 |
5 | # Provides the functionality to download template catalogs from the remote repository
6 | class CatalogDownloader
7 |
8 | # Updates all of the template catalogs and returns their filepaths.
9 | # If there is a Rambafile in the current directory, it also updates all of the catalogs specified there.
10 | #
11 | # @return [Array] An array of filepaths to downloaded catalogs
12 | def update_all_catalogs_and_return_filepaths
13 | does_rambafile_exist = Dir[RAMBAFILE_NAME].count > 0
14 |
15 | if does_rambafile_exist
16 | rambafile = YAML.load_file(RAMBAFILE_NAME)
17 | catalogs = rambafile[CATALOGS_KEY]
18 | end
19 |
20 | terminator = CatalogTerminator.new
21 | terminator.remove_all_catalogs
22 |
23 | catalog_paths = [download_catalog(GENERAMBA_CATALOG_NAME, RAMBLER_CATALOG_REPO)]
24 |
25 | if catalogs != nil && catalogs.count > 0
26 | catalogs.each do |catalog_url|
27 | catalog_name = catalog_url.split('://').last
28 | catalog_name = catalog_name.gsub('/', '-');
29 | catalog_paths.push(download_catalog(catalog_name, catalog_url))
30 | end
31 | end
32 | return catalog_paths
33 | end
34 |
35 | # Clones a template catalog from a remote repository
36 | #
37 | # @param name [String] The name of the template catalog
38 | # @param url [String] The url of the repository
39 | #
40 | # @return [Pathname] A filepath to the downloaded catalog
41 | def download_catalog(name, url)
42 | catalogs_local_path = Pathname.new(ENV['HOME'])
43 | .join(GENERAMBA_HOME_DIR)
44 | .join(CATALOGS_DIR)
45 | current_catalog_path = catalogs_local_path
46 | .join(name)
47 |
48 | if File.exists?(current_catalog_path)
49 | g = Git.open(current_catalog_path)
50 | g.pull
51 | else
52 | Git.clone(url, name, :path => catalogs_local_path)
53 | end
54 |
55 | return current_catalog_path
56 | end
57 | end
58 | end
--------------------------------------------------------------------------------
/lib/generamba/template/helpers/catalog_template_list_helper.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 |
3 | # Provides the functionality to list all of the templates, available in the catalog
4 | class CatalogTemplateListHelper
5 |
6 | # Finds out all of the templates located in a catalog
7 | #
8 | # @param catalog_path [Pathname] The path to a template catalog
9 | #
10 | # @return [Array] An array with template names
11 | def obtain_all_templates_from_a_catalog(catalog_path)
12 | template_names = []
13 | catalog_path.children.select { |child|
14 | File.directory?(child) && child.split.last.to_s[0] != '.'
15 | }.map { |template_path|
16 | template_path.split.last.to_s
17 | }.each { |template_name|
18 | template_names.push(template_name)
19 | }
20 | return template_names
21 | end
22 | end
23 | end
--------------------------------------------------------------------------------
/lib/generamba/template/helpers/catalog_template_search_helper.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 |
3 | # Provides the functionality to search templates, in catalogs
4 | class CatalogTemplateSearchHelper
5 |
6 | # Finds out all of the templates located in a catalog
7 | #
8 | # @param catalog_path [Pathname] The path to a template catalog
9 | #
10 | # @return [Array] An array with template names
11 | def search_templates_in_a_catalog(catalog_path, search_term)
12 | template_names = []
13 |
14 | catalog_path.children.select { |child|
15 | File.directory?(child) && child.split.last.to_s[0] != '.'
16 | }.map { |template_path|
17 | template_path.split.last.to_s
18 | }.select { |template_name|
19 | template_name.include?(search_term)
20 | }.each { |template_name|
21 | template_names.push(template_name)
22 | }
23 |
24 | return template_names
25 | end
26 | end
27 | end
--------------------------------------------------------------------------------
/lib/generamba/template/helpers/catalog_terminator.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 |
3 | # Provides a functionality to terminate all previously installed catalogs
4 | #
5 | # @return [Void]
6 | class CatalogTerminator
7 | def remove_all_catalogs
8 | catalogs_path = Pathname.new(ENV['HOME'])
9 | .join(GENERAMBA_HOME_DIR)
10 | .join(CATALOGS_DIR)
11 | if Dir.exist?(catalogs_path) == false
12 | FileUtils.mkdir_p catalogs_path
13 | end
14 | catalogs_path.children.select { |child|
15 | child.directory? && child.split.last.to_s[0] != '.'
16 | }.each { |catalog_path|
17 | FileUtils.rm_rf(catalog_path)
18 | }
19 | end
20 | end
21 | end
--------------------------------------------------------------------------------
/lib/generamba/template/helpers/rambaspec_validator.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 |
3 | # Provides methods that validate .rambaspec file existance and structure
4 | class RambaspecValidator
5 |
6 | # Validates the existance of a .rambaspec file for a given template
7 | #
8 | # @param template_name [String] The name of the template
9 | # @param template_path [String] The local filepath to the template
10 | #
11 | # @return [Bool]
12 | def self.validate_spec_existance(template_name, template_path)
13 | local_spec_path = self.obtain_spec_path(template_name, template_path)
14 | File.file?(local_spec_path)
15 | end
16 |
17 | # Validates the structure of a .rambaspec file for a given template
18 | #
19 | # @param template_name [String] The name of the template
20 | # @param template_path [String] The local filepath to the template
21 | #
22 | # @return [Bool]
23 | def self.validate_spec(template_name, template_path)
24 | spec_path = self.obtain_spec_path(template_name, template_path)
25 |
26 | spec_source = IO.read(spec_path)
27 | spec_template = Liquid::Template.parse(spec_source)
28 | spec_content = spec_template.render
29 | spec = YAML.load(spec_content)
30 |
31 | is_spec_valid =
32 | spec[TEMPLATE_NAME_KEY] != nil &&
33 | spec[TEMPLATE_AUTHOR_KEY] != nil &&
34 | spec[TEMPLATE_VERSION_KEY] != nil &&
35 | (spec[TEMPLATE_CODE_FILES_KEY] != nil || spec[TEMPLATE_TEST_FILES_KEY] != nil)
36 | return is_spec_valid
37 | end
38 |
39 | private
40 |
41 | # Returns a filepath for a given .rambaspec filename
42 | #
43 | # @param template_name [String] The name of the template
44 | # @param template_path [String] The local filepath to the template
45 | #
46 | # @return [Bool]
47 | def self.obtain_spec_path(template_name, template_path)
48 | spec_filename = template_name + RAMBASPEC_EXTENSION
49 | Pathname.new(template_path).join(spec_filename)
50 | end
51 | end
52 | end
--------------------------------------------------------------------------------
/lib/generamba/template/installer/abstract_installer.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 |
3 | # Abstract template installer class
4 | class AbstractInstaller
5 | def install_template(template_declaration)
6 | raise 'Abstract Method - you should implement it in the concrete subclass'
7 | end
8 | end
9 | end
--------------------------------------------------------------------------------
/lib/generamba/template/installer/catalog_installer.rb:
--------------------------------------------------------------------------------
1 | require 'generamba/template/installer/abstract_installer.rb'
2 | require 'generamba/template/helpers/rambaspec_validator.rb'
3 | require 'fileutils'
4 | require 'tmpdir'
5 |
6 | module Generamba
7 |
8 | # Incapsulates the logic of installing Generamba templates from the template catalog
9 | class CatalogInstaller < AbstractInstaller
10 | def install_template(template_declaration)
11 | template_name = template_declaration.name
12 | puts("Installing #{template_name}...")
13 |
14 | template_name = template_declaration.name
15 | catalogs_path = Pathname.new(ENV['HOME'])
16 | .join(GENERAMBA_HOME_DIR)
17 | .join(CATALOGS_DIR)
18 |
19 | catalog_path = catalogs_path.children.select { |child|
20 | child.directory? && child.split.last.to_s[0] != '.'
21 | }.select { |catalog_path|
22 | template_path = browse_catalog_for_a_template(catalog_path, template_name)
23 | template_path != nil
24 | }.first
25 |
26 | if catalog_path == nil
27 | error_description = "Cannot find #{template_name} in any catalog. Try another name.".red
28 | puts(error_description)
29 | return
30 | end
31 |
32 | template_path = catalog_path.join(template_name)
33 | rambaspec_exist = Generamba::RambaspecValidator.validate_spec_existance(template_name, template_path)
34 | unless rambaspec_exist
35 | error_description = "Cannot find #{template_name + RAMBASPEC_EXTENSION} in the template catalog #{catalog_path}. Try another name.".red
36 | puts(error_description)
37 | return
38 | end
39 |
40 | rambaspec_valid = Generamba::RambaspecValidator.validate_spec(template_name, template_path)
41 | unless rambaspec_valid
42 | error_description = "#{template_name + RAMBASPEC_EXTENSION} is not valid.".red
43 | puts(error_description)
44 | return
45 | end
46 |
47 | install_path = Pathname.new(TEMPLATES_FOLDER)
48 | .join(template_name)
49 | FileUtils.mkdir_p install_path
50 |
51 | src = template_path.to_s + '/.'
52 | FileUtils.cp_r(src, install_path)
53 | end
54 |
55 | private
56 |
57 | # Browses a given catalog and returns a template path
58 | #
59 | # @param catalog_path [Pathname] A path to a catalog
60 | # @param template_name [String] A name of the template
61 | #
62 | # @return [Pathname] A path to a template, if found
63 | def browse_catalog_for_a_template(catalog_path, template_name)
64 | template_path = catalog_path.join(template_name)
65 |
66 | if Dir.exist?(template_path)
67 | return template_path
68 | end
69 |
70 | return nil
71 | end
72 | end
73 | end
--------------------------------------------------------------------------------
/lib/generamba/template/installer/local_installer.rb:
--------------------------------------------------------------------------------
1 | require 'generamba/template/installer/abstract_installer.rb'
2 | require 'generamba/template/helpers/rambaspec_validator.rb'
3 |
4 | module Generamba
5 |
6 | # Incapsulates the logic of verifying and installing local templates
7 | class LocalInstaller < AbstractInstaller
8 | def install_template(template_declaration)
9 | template_name = template_declaration.name
10 | puts("Installing #{template_name}...")
11 |
12 | local_path = template_declaration.local
13 | rambaspec_exist = Generamba::RambaspecValidator.validate_spec_existance(template_name, local_path)
14 |
15 | unless rambaspec_exist
16 | error_description = "Cannot find #{template_name + RAMBASPEC_EXTENSION} in the specified directory. Try another path or name.".red
17 | raise StandardError.new(error_description)
18 | end
19 |
20 | rambaspec_valid = Generamba::RambaspecValidator.validate_spec(template_name, local_path)
21 | unless rambaspec_valid
22 | error_description = "#{template_name + RAMBASPEC_EXTENSION} is not valid.".red
23 | raise StandardError.new(error_description)
24 | end
25 |
26 | install_path = Pathname.new(TEMPLATES_FOLDER)
27 | .join(template_name)
28 | FileUtils.mkdir_p install_path
29 | FileUtils.copy_entry(local_path, install_path)
30 | end
31 | end
32 | end
--------------------------------------------------------------------------------
/lib/generamba/template/installer/remote_installer.rb:
--------------------------------------------------------------------------------
1 | require 'generamba/template/installer/abstract_installer.rb'
2 | require 'generamba/template/helpers/rambaspec_validator.rb'
3 | require 'git'
4 | require 'fileutils'
5 | require 'tmpdir'
6 |
7 | module Generamba
8 |
9 | # Incapsulates the logic of fetching remote templates, verifying and installing them
10 | class RemoteInstaller < AbstractInstaller
11 | def install_template(template_declaration)
12 | template_name = template_declaration.name
13 | puts("Installing #{template_name}...")
14 |
15 | repo_url = template_declaration.git
16 | repo_branch = template_declaration.branch
17 |
18 | temp_path = Dir.tmpdir()
19 | template_dir = Pathname.new(temp_path).join(template_name)
20 |
21 | if repo_branch != nil
22 | Git.export(repo_url, template_name, :branch => repo_branch, :path => temp_path)
23 | else
24 | Git.clone(repo_url, template_name, :path => temp_path)
25 | end
26 |
27 | template_path = "#{template_dir}"
28 |
29 | rambaspec_exist = Generamba::RambaspecValidator.validate_spec_existance(template_name, template_path)
30 | unless rambaspec_exist
31 | FileUtils.rm_rf(temp_path)
32 | error_description = "Cannot find #{template_name + RAMBASPEC_EXTENSION} in the root directory of specified repository.".red
33 | raise StandardError.new(error_description)
34 | end
35 |
36 | rambaspec_valid = Generamba::RambaspecValidator.validate_spec(template_name, template_path)
37 | unless rambaspec_valid
38 | error_description = "#{template_name + RAMBASPEC_EXTENSION} is not valid.".red
39 | raise StandardError.new(error_description)
40 | end
41 |
42 | install_path = Pathname.new(TEMPLATES_FOLDER)
43 | .join(template_name)
44 | FileUtils.mkdir_p install_path
45 | FileUtils.copy_entry(template_path, install_path)
46 |
47 | FileUtils.rm_rf(temp_path)
48 | end
49 | end
50 | end
--------------------------------------------------------------------------------
/lib/generamba/template/installer/template_installer_factory.rb:
--------------------------------------------------------------------------------
1 | require 'generamba/template/processor/template_declaration'
2 |
3 | module Generamba
4 |
5 | # Factory that creates a proper installer for a given template type
6 | class TemplateInstallerFactory
7 |
8 | # Provides the appropriate strategy for a given template type
9 | def installer_for_type(type)
10 | case type
11 | when TemplateDeclarationType::LOCAL_TEMPLATE
12 | return Generamba::LocalInstaller.new
13 | when TemplateDeclarationType::REMOTE_TEMPLATE
14 | return Generamba::RemoteInstaller.new
15 | when TemplateDeclarationType::CATALOG_TEMPLATE
16 | return Generamba::CatalogInstaller.new
17 | else
18 | return nil
19 | end
20 | end
21 | end
22 | end
--------------------------------------------------------------------------------
/lib/generamba/template/processor/template_declaration.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 |
3 | # This class acts as an Enumeration for TemplateDeclaration types
4 | class TemplateDeclarationType
5 | # A local template - usually it's stored somewhere outside the current project directory
6 | LOCAL_TEMPLATE = 0
7 |
8 | # A remote template - it's stored in a remote Git repository
9 | REMOTE_TEMPLATE = 1
10 |
11 | # A template from our shared catalog
12 | CATALOG_TEMPLATE = 2
13 | end
14 |
15 | # Describes a Generamba template declaration model
16 | class TemplateDeclaration
17 |
18 | attr_reader :name, :local, :git, :branch, :type
19 |
20 | def initialize(template_hash)
21 | @name = template_hash[TEMPLATE_DECLARATION_NAME_KEY]
22 | @local = template_hash[TEMPLATE_DECLARATION_LOCAL_KEY]
23 | @git = template_hash[TEMPLATE_DECLARATION_GIT_KEY]
24 | @branch = template_hash[TEMPLATE_DECLARATION_BRANCH_KEY]
25 |
26 | @type = TemplateDeclarationType::LOCAL_TEMPLATE if @local
27 | @type = TemplateDeclarationType::REMOTE_TEMPLATE if @git
28 | @type = TemplateDeclarationType::CATALOG_TEMPLATE if @git == nil && @local == nil
29 | end
30 |
31 | def install(strategy)
32 | strategy.install_template(self)
33 | end
34 |
35 | end
36 | end
--------------------------------------------------------------------------------
/lib/generamba/template/processor/template_processor.rb:
--------------------------------------------------------------------------------
1 | require 'generamba/template/processor/template_declaration.rb'
2 | require 'generamba/template/installer/local_installer.rb'
3 | require 'generamba/template/installer/remote_installer.rb'
4 | require 'generamba/template/installer/catalog_installer.rb'
5 | require 'generamba/template/helpers/catalog_downloader.rb'
6 | require 'generamba/template/helpers/catalog_terminator'
7 | require 'git'
8 |
9 | module Generamba
10 |
11 | # Incapsulates logic of processing templates declaration section from Rambafile
12 | class TemplateProcessor
13 |
14 | def initialize(catalog_downloader, installer_factory)
15 | @catalog_downloader = catalog_downloader
16 | @installer_factory = installer_factory
17 | end
18 |
19 | # This method parses Rambafile, serializes templates hashes into model objects and install them
20 | def install_templates(rambafile)
21 | # We always clear previously installed templates to avoid conflicts in different versions
22 | clear_installed_templates
23 |
24 | templates = rambafile[TEMPLATES_KEY]
25 |
26 | if !templates || templates.count == 0
27 | puts 'You must specify at least one template in Rambafile under the key *templates*'.red
28 | return
29 | end
30 |
31 | # Mapping hashes to model objects
32 | templates = rambafile[TEMPLATES_KEY].map { |template_hash|
33 | Generamba::TemplateDeclaration.new(template_hash)
34 | }
35 |
36 | catalogs = rambafile[CATALOGS_KEY]
37 | # If there is at least one template from catalogs, we should update our local copy of the catalog
38 | update_catalogs_if_needed(catalogs, templates)
39 |
40 | templates.each do |template_declaration|
41 | strategy = @installer_factory.installer_for_type(template_declaration.type)
42 | template_declaration.install(strategy)
43 | end
44 | end
45 |
46 | private
47 |
48 | # Clears all of the currently installed templates
49 | def clear_installed_templates
50 | install_path = Pathname.new(TEMPLATES_FOLDER)
51 | FileUtils.rm_rf(Dir.glob(install_path))
52 | end
53 |
54 | # Clones remote template catalogs to the local directory
55 | def update_catalogs_if_needed(catalogs, templates)
56 | needs_update = templates.any? {|template| template.type == TemplateDeclarationType::CATALOG_TEMPLATE}
57 |
58 | return unless needs_update
59 |
60 | terminator = CatalogTerminator.new
61 | terminator.remove_all_catalogs
62 | puts('Updating shared generamba-catalog specs...')
63 | @catalog_downloader.download_catalog(GENERAMBA_CATALOG_NAME, RAMBLER_CATALOG_REPO)
64 |
65 | return unless catalogs != nil && catalogs.count > 0
66 |
67 | catalogs.each do |catalog_url|
68 | catalog_name = catalog_url.split('://').last
69 | catalog_name = catalog_name.gsub('/', '-');
70 | puts("Updating #{catalog_name} specs...")
71 | @catalog_downloader.download_catalog(catalog_name, catalog_url)
72 | end
73 | end
74 | end
75 | end
--------------------------------------------------------------------------------
/lib/generamba/tools/string-colorize.rb:
--------------------------------------------------------------------------------
1 | # Adds a number of methods for colorizing output strings
2 | class String
3 |
4 | def colorize(color_code)
5 | "\e[#{color_code}m#{self}\e[0m"
6 | end
7 |
8 | def red
9 | colorize(31)
10 | end
11 |
12 | def green
13 | colorize(32)
14 | end
15 |
16 | def yellow
17 | colorize(33)
18 | end
19 |
20 | def blue
21 | colorize(34)
22 | end
23 | end
--------------------------------------------------------------------------------
/lib/generamba/version.rb:
--------------------------------------------------------------------------------
1 | module Generamba
2 | VERSION = '1.6.0'
3 | RELEASE_DATE = '11.08.2019'
4 | RELEASE_LINK = "https://github.com/rambler-digital-solutions/Generamba/releases/tag/#{VERSION}"
5 | end
6 |
--------------------------------------------------------------------------------
/spec/catalog_downloader_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative 'spec_helper'
2 |
3 | describe 'CatalogDownloader' do
4 | describe 'method download_catalog' do
5 |
6 | it 'should pull catalog from remote repository if directory exists' do
7 | catalog_name = 'catalog'
8 | catalog_url = 'https://github.com/rambler-digital-solutions/generamba-catalog'
9 |
10 | allow(File).to receive(:exists?) { true }
11 |
12 | git = instance_double("Base")
13 |
14 | allow(Git).to receive(:open) { git }
15 | allow(git).to receive(:pull)
16 | expect(git).to receive(:pull)
17 |
18 | downloader = Generamba::CatalogDownloader.new
19 | downloader.download_catalog(catalog_name, catalog_url)
20 | end
21 |
22 | it 'should clone catalog from remote repository if directory not exists' do
23 | catalog_name = 'catalog'
24 | catalog_url = 'https://github.com/rambler-digital-solutions/generamba-catalog'
25 |
26 | allow(File).to receive(:exists?) { false }
27 |
28 | allow(Git).to receive(:clone)
29 | expect(Git).to receive(:clone).with(catalog_url, catalog_name, any_args)
30 |
31 | downloader = Generamba::CatalogDownloader.new
32 | downloader.download_catalog(catalog_name, catalog_url)
33 | end
34 |
35 | it 'should return local catalog directory' do
36 | catalog_name = 'catalog'
37 | catalog_url = 'https://github.com/rambler-digital-solutions/generamba-catalog'
38 | catalogs_local_path = Pathname.new(ENV['HOME'])
39 | .join(Generamba::GENERAMBA_HOME_DIR)
40 | .join(Generamba::CATALOGS_DIR)
41 | current_catalog_path = catalogs_local_path
42 | .join(catalog_name)
43 |
44 | allow(Git).to receive(:clone)
45 |
46 | downloader = Generamba::CatalogDownloader.new
47 | result = downloader.download_catalog(catalog_name, catalog_url)
48 | expect(result).to eq(current_catalog_path)
49 | end
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/spec/catalog_installer_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative 'spec_helper'
2 | require 'generamba/template/processor/template_declaration'
3 |
4 | describe 'method install_template' do
5 |
6 | it 'should install template from shared catalog' do
7 | template_name = 'test'
8 | catalog_path = Pathname.new(ENV['HOME'])
9 | .join(Generamba::GENERAMBA_HOME_DIR)
10 | .join(Generamba::CATALOGS_DIR)
11 | .join(Generamba::GENERAMBA_CATALOG_NAME)
12 | template_path = catalog_path.join(template_name)
13 |
14 | template_install_path = Pathname.new(Generamba::TEMPLATES_FOLDER)
15 | .join(template_name)
16 |
17 | allow(Generamba::RambaspecValidator).to receive(:validate_spec).and_return(true)
18 | allow(Generamba::RambaspecValidator).to receive(:validate_spec_existance).and_return(true)
19 | FakeFS do
20 | FileUtils.mkdir_p template_path
21 |
22 | declaration = Generamba::TemplateDeclaration.new({Generamba::TEMPLATE_DECLARATION_NAME_KEY => 'test'})
23 | installer = Generamba::CatalogInstaller.new
24 | installer.install_template(declaration)
25 |
26 | result = Dir.exist?(template_install_path)
27 | expect(result).to eq(true)
28 | end
29 | end
30 |
31 | it 'should install template from other catalog' do
32 | template_name = 'test'
33 | catalog_name = 'custom_catalog'
34 | shared_catalog_path = Pathname.new(ENV['HOME'])
35 | .join(Generamba::GENERAMBA_HOME_DIR)
36 | .join(Generamba::CATALOGS_DIR)
37 | .join(Generamba::GENERAMBA_CATALOG_NAME)
38 | catalog_path = Pathname.new(ENV['HOME'])
39 | .join(Generamba::GENERAMBA_HOME_DIR)
40 | .join(Generamba::CATALOGS_DIR)
41 | .join(catalog_name)
42 | template_path = catalog_path.join(template_name)
43 |
44 | template_install_path = Pathname.new(Generamba::TEMPLATES_FOLDER)
45 | .join(template_name)
46 |
47 | allow(Generamba::RambaspecValidator).to receive(:validate_spec).and_return(true)
48 | allow(Generamba::RambaspecValidator).to receive(:validate_spec_existance) do |name, path|
49 | result = false
50 | if template_path.to_s == path.to_s
51 | result = true
52 | end
53 | result
54 | end
55 |
56 | FakeFS do
57 | FileUtils.mkdir_p template_path
58 | FileUtils.mkdir_p shared_catalog_path
59 |
60 | declaration = Generamba::TemplateDeclaration.new({Generamba::TEMPLATE_DECLARATION_NAME_KEY => 'test'})
61 | installer = Generamba::CatalogInstaller.new
62 | installer.install_template(declaration)
63 |
64 | result = Dir.exist?(template_install_path)
65 | expect(result).to eq(true)
66 | end
67 | end
68 | end
--------------------------------------------------------------------------------
/spec/catalog_template_list_helper_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative 'spec_helper'
2 | require 'generamba/template/helpers/catalog_template_list_helper'
3 |
4 | describe 'method obtain_all_templates_from_a_catalog' do
5 |
6 | it 'should return 0 template names for empty catalog' do
7 | test_catalog_path = Pathname.new('test-path/catalog')
8 | FakeFS do
9 | FileUtils.mkdir_p test_catalog_path
10 |
11 | list_helper = Generamba::CatalogTemplateListHelper.new
12 | result = list_helper.obtain_all_templates_from_a_catalog(test_catalog_path)
13 | expect(result.count).to eq(0)
14 | end
15 | end
16 |
17 | it 'should return template names for non-empty catalog' do
18 | test_catalog_path = Pathname.new('test-path/catalog')
19 | test_template_count = 5
20 | FakeFS do
21 | FileUtils.mkdir_p test_catalog_path
22 | for i in 1..test_template_count
23 | FileUtils.mkdir_p test_catalog_path.join(i.to_s)
24 | end
25 |
26 | list_helper = Generamba::CatalogTemplateListHelper.new
27 | result = list_helper.obtain_all_templates_from_a_catalog(test_catalog_path)
28 | expect(result.count).to eq(test_template_count)
29 | end
30 | end
31 | end
--------------------------------------------------------------------------------
/spec/catalog_template_search_helper_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative 'spec_helper'
2 | require 'generamba/template/helpers/catalog_template_search_helper'
3 |
4 | describe 'method search_templates_in_a_catalog' do
5 | it 'should return zero templates if no matches' do
6 | test_catalog_path = Pathname.new('test-path/catalog')
7 | FakeFS do
8 | FileUtils.mkdir_p test_catalog_path
9 |
10 | search_helper = Generamba::CatalogTemplateSearchHelper.new
11 | result = search_helper.search_templates_in_a_catalog(test_catalog_path, 'viper')
12 | expect(result.count).to eq(0)
13 | end
14 | end
15 |
16 | it 'should return templates if there are matches' do
17 | test_catalog_path = Pathname.new('test-path/catalog')
18 | test_search_term = 'viper'
19 | test_viper_template_path = test_catalog_path.join("#{test_search_term}-template")
20 | FakeFS do
21 | FileUtils.mkdir_p test_viper_template_path
22 |
23 | search_helper = Generamba::CatalogTemplateSearchHelper.new
24 | result = search_helper.search_templates_in_a_catalog(test_catalog_path, test_search_term)
25 | expect(result.count).to eq(1)
26 | end
27 | end
28 | end
--------------------------------------------------------------------------------
/spec/dependency_checker_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative 'spec_helper'
2 |
3 | describe 'DependencyChecker' do
4 | before(:each) do
5 | @checker = Generamba::DependencyChecker
6 | end
7 |
8 | describe 'method check_all_required_dependencies_has_in_podfile' do
9 | it 'should do nothing' do
10 | dependencies = ['ViperMcFlurry']
11 | podfile_path = 'Podfile'
12 |
13 | expect(STDOUT).not_to receive(:puts).with("[Warning] Dependencies #{dependencies} missed in Podfile".yellow)
14 |
15 | @checker.check_all_required_dependencies_has_in_podfile(dependencies, nil)
16 | @checker.check_all_required_dependencies_has_in_podfile(nil, podfile_path)
17 | end
18 |
19 | it 'should show warning message' do
20 | dependencies = ['ViperMcFlurry']
21 | podfile_path = 'Podfile'
22 |
23 | allow(Pod::Podfile).to receive(:from_file).and_return(Pod::Podfile.new)
24 | expect(STDOUT).to receive(:puts).with("[Warning] Dependencies #{dependencies} missed in Podfile".yellow)
25 |
26 | @checker.check_all_required_dependencies_has_in_podfile(dependencies, podfile_path)
27 | end
28 | end
29 |
30 | describe 'method check_all_required_dependencies_has_in_cartfile' do
31 | it 'should do nothing' do
32 | dependencies = ['ViperMcFlurry']
33 | cartfile_path = 'Cartfile'
34 |
35 | expect(STDOUT).not_to receive(:puts).with("[Warning] Dependencies #{dependencies} missed in Cartfile".yellow)
36 |
37 | @checker.check_all_required_dependencies_has_in_cartfile(dependencies, nil)
38 | @checker.check_all_required_dependencies_has_in_cartfile(nil, cartfile_path)
39 | end
40 |
41 | it 'should show warning message if dependency missing' do
42 | dependencies = ['ViperMcFlurry']
43 | cartfile_path = 'Cartfile'
44 |
45 | allow(File).to receive(:read).and_return('Typhoon')
46 | expect(STDOUT).to receive(:puts).with("[Warning] Dependencies #{dependencies} missed in Cartfile".yellow)
47 |
48 | @checker.check_all_required_dependencies_has_in_cartfile(dependencies, cartfile_path)
49 | end
50 |
51 | it 'should not show warning message if dependency is in place' do
52 | dependencies = ['ViperMcFlurry']
53 | cartfile_path = 'Cartfile'
54 |
55 | allow(File).to receive(:read).and_return('github "Rambler-iOS/ViperMcFlurry"')
56 | expect(STDOUT).not_to receive(:puts).with("[Warning] Dependencies #{dependencies} missed in Cartfile".yellow)
57 |
58 | @checker.check_all_required_dependencies_has_in_cartfile(dependencies, cartfile_path)
59 | end
60 | end
61 |
62 | end
--------------------------------------------------------------------------------
/spec/gen_command_table_parameters_formatter_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative 'spec_helper'
2 | require 'json'
3 | require 'generamba/code_generation/code_module.rb'
4 | require 'generamba/constants/rambafile_constants.rb'
5 |
6 | describe 'GenCommandTableParametersFormatter' do
7 |
8 | describe 'method prepare_parameters_for_displaying' do
9 | it 'should convert array of hash to array of strings' do
10 | expected_params = {}
11 |
12 | expected_params['Targets'] = 'Target'
13 | expected_params['Module path'] = Pathname.new('Project/name')
14 | expected_params['Module group path'] = Pathname.new('Project/Modules/name')
15 | expected_params['Test targets'] = 'TargetTests'
16 | expected_params['Test file path'] = Pathname.new('ProjectTests/name')
17 | expected_params['Test group path'] = Pathname.new('ProjectTests/Modules/name')
18 | expected_params['Template'] = 'Template'
19 | expected_params['Custom parameters'] = {:key => 'value'}.to_json
20 |
21 | rambafile = {}
22 | rambafile[Generamba::PROJECT_NAME_KEY] = 'project'
23 | rambafile[Generamba::PROJECT_FILE_PATH_KEY] = 'file_path'
24 | rambafile[Generamba::PROJECT_GROUP_PATH_KEY] = 'group_path'
25 | rambafile[Generamba::PROJECT_TARGET_KEY] = 'Target'
26 | rambafile[Generamba::PROJECT_FILE_PATH_KEY] = 'Project'
27 | rambafile[Generamba::PROJECT_GROUP_PATH_KEY] = 'Project/Modules'
28 | rambafile[Generamba::TEST_TARGET_KEY] = 'TargetTests'
29 | rambafile[Generamba::TEST_FILE_PATH_KEY] = 'ProjectTests'
30 | rambafile[Generamba::TEST_GROUP_PATH_KEY] = 'ProjectTests/Modules'
31 |
32 | options = {}
33 | options[:custom_parameters] = {:key => 'value'}
34 |
35 | code_module = Generamba::CodeModule.new('name', rambafile, options)
36 | template_name = 'Template'
37 |
38 | params = Generamba::GenCommandTableParametersFormatter.prepare_parameters_for_displaying(code_module, template_name)
39 |
40 | expect(params).to eq(expected_params)
41 | end
42 | end
43 |
44 | end
45 |
--------------------------------------------------------------------------------
/spec/generamba_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative 'spec_helper'
2 |
3 | describe Generamba do
4 | it 'has a version number' do
5 | expect(Generamba::VERSION).not_to be nil
6 | end
7 |
8 | end
9 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2 | require 'generamba'
3 |
--------------------------------------------------------------------------------
/spec/template_installer_factory_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative 'spec_helper'
2 | require 'generamba/template/installer/template_installer_factory'
3 | require 'generamba/template/processor/template_declaration'
4 |
5 | describe 'TemplateInstallerFactory' do
6 | describe 'method installer_for_type' do
7 | subject(:factory) { Generamba::TemplateInstallerFactory.new }
8 | it 'returns local installer' do
9 | installer = factory.installer_for_type(Generamba::TemplateDeclarationType::LOCAL_TEMPLATE)
10 | result = installer.is_a?(Generamba::LocalInstaller)
11 |
12 | expect(result).to eq(true)
13 | end
14 |
15 | it 'returns remote installer' do
16 | installer = factory.installer_for_type(Generamba::TemplateDeclarationType::REMOTE_TEMPLATE)
17 | result = installer.is_a?(Generamba::RemoteInstaller)
18 |
19 | expect(result).to eq(true)
20 | end
21 |
22 | it 'returns catalog installer' do
23 | installer = factory.installer_for_type(Generamba::TemplateDeclarationType::CATALOG_TEMPLATE)
24 | result = installer.is_a?(Generamba::CatalogInstaller)
25 |
26 | expect(result).to eq(true)
27 | end
28 | end
29 |
30 | end
31 |
--------------------------------------------------------------------------------
/spec/template_processor_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative 'spec_helper'
2 | require 'fakefs/spec_helpers'
3 |
4 | describe 'TemplateProcessor' do
5 | include FakeFS::SpecHelpers
6 |
7 | describe 'method install_templates' do
8 | it 'should clear previously installed templates' do
9 | FakeFS do
10 | installed_templates_path = Pathname.new(Generamba::TEMPLATES_FOLDER)
11 | FileUtils.mkdir_p(installed_templates_path)
12 |
13 | processor = Generamba::TemplateProcessor.new(nil, nil)
14 | processor.install_templates({})
15 | result = installed_templates_path.exist?
16 |
17 | expect(result).to eq(false)
18 | end
19 | end
20 |
21 | it 'should check for templates declaration' do
22 | expect(STDOUT).to receive(:puts).with('You must specify at least one template in Rambafile under the key *templates*'.red)
23 | processor = Generamba::TemplateProcessor.new(nil, nil)
24 | processor.install_templates({})
25 | end
26 |
27 | it 'should update shared catalog if needed' do
28 | rambafile = {
29 | Generamba::TEMPLATES_KEY => [
30 | {
31 | Generamba::TEMPLATE_DECLARATION_NAME_KEY => 'test'
32 | }
33 | ]
34 | }
35 | downloader = instance_double('Generamba::CatalogDownloader')
36 | allow(downloader).to receive(:download_catalog)
37 |
38 | mock_installer = instance_double('Generamba::CatalogInstaller')
39 | allow(mock_installer).to receive(:install_template)
40 | installer_factory = instance_double('Generamba::TemplateInstallerFactory')
41 | allow(installer_factory).to receive(:installer_for_type).and_return(mock_installer)
42 |
43 | processor = Generamba::TemplateProcessor.new(downloader, installer_factory)
44 | processor.install_templates(rambafile)
45 |
46 | expect(downloader).to have_received(:download_catalog).with(Generamba::GENERAMBA_CATALOG_NAME, Generamba::RAMBLER_CATALOG_REPO)
47 | end
48 |
49 | it 'should update other catalogs if needed' do
50 | test_catalog_url = 'http://github.com/catalog1'
51 | test_catalog_name = test_catalog_url.split('://').last
52 | test_catalog_name = test_catalog_name.gsub('/', '-');
53 | rambafile = {
54 | Generamba::TEMPLATES_KEY => [
55 | {
56 | Generamba::TEMPLATE_DECLARATION_NAME_KEY => 'test'
57 | }
58 | ],
59 | Generamba::CATALOGS_KEY => [
60 | test_catalog_url
61 | ]
62 | }
63 |
64 | downloader = instance_double('Generamba::CatalogDownloader')
65 | allow(downloader).to receive(:download_catalog)
66 |
67 | mock_installer = instance_double('Generamba::CatalogInstaller')
68 | allow(mock_installer).to receive(:install_template)
69 | installer_factory = instance_double('Generamba::TemplateInstallerFactory')
70 | allow(installer_factory).to receive(:installer_for_type).and_return(mock_installer)
71 |
72 | processor = Generamba::TemplateProcessor.new(downloader, installer_factory)
73 | processor.install_templates(rambafile)
74 | expect(downloader).to have_received(:download_catalog).with(test_catalog_name, test_catalog_url)
75 | end
76 |
77 | it 'should install local templates' do
78 | rambafile = {
79 | Generamba::TEMPLATES_KEY => [
80 | {
81 | Generamba::TEMPLATE_DECLARATION_NAME_KEY => 'test',
82 | Generamba::TEMPLATE_DECLARATION_LOCAL_KEY => 'path'
83 | }
84 | ]
85 | }
86 |
87 | mock_installer = instance_double('Generamba::LocalInstaller')
88 | allow(mock_installer).to receive(:install_template)
89 | installer_factory = instance_double('Generamba::TemplateInstallerFactory')
90 | allow(installer_factory).to receive(:installer_for_type).and_return(mock_installer)
91 |
92 | processor = Generamba::TemplateProcessor.new(nil, installer_factory)
93 | processor.install_templates(rambafile)
94 |
95 | expect(installer_factory).to have_received(:installer_for_type).with(Generamba::TemplateDeclarationType::LOCAL_TEMPLATE)
96 | expect(mock_installer).to have_received(:install_template)
97 | end
98 |
99 | it 'should install remote templates' do
100 | rambafile = {
101 | Generamba::TEMPLATES_KEY => [
102 | {
103 | Generamba::TEMPLATE_DECLARATION_NAME_KEY => 'test',
104 | Generamba::TEMPLATE_DECLARATION_GIT_KEY => 'path'
105 | }
106 | ]
107 | }
108 |
109 | mock_installer = instance_double('Generamba::RemoteInstaller')
110 | allow(mock_installer).to receive(:install_template)
111 | installer_factory = instance_double('Generamba::TemplateInstallerFactory')
112 | allow(installer_factory).to receive(:installer_for_type).and_return(mock_installer)
113 |
114 | processor = Generamba::TemplateProcessor.new(nil, installer_factory)
115 | processor.install_templates(rambafile)
116 |
117 | expect(installer_factory).to have_received(:installer_for_type).with(Generamba::TemplateDeclarationType::REMOTE_TEMPLATE)
118 | expect(mock_installer).to have_received(:install_template)
119 | end
120 |
121 | it 'should install catalog templates' do
122 | rambafile = {
123 | Generamba::TEMPLATES_KEY => [
124 | {
125 | Generamba::TEMPLATE_DECLARATION_NAME_KEY => 'test'
126 | }
127 | ]
128 | }
129 | downloader = instance_double('Generamba::CatalogDownloader')
130 | allow(downloader).to receive(:download_catalog)
131 |
132 | mock_installer = instance_double('Generamba::CatalogInstaller')
133 | allow(mock_installer).to receive(:install_template)
134 | installer_factory = instance_double('Generamba::TemplateInstallerFactory')
135 | allow(installer_factory).to receive(:installer_for_type).and_return(mock_installer)
136 |
137 | processor = Generamba::TemplateProcessor.new(downloader, installer_factory)
138 | processor.install_templates(rambafile)
139 |
140 | expect(installer_factory).to have_received(:installer_for_type).with(Generamba::TemplateDeclarationType::CATALOG_TEMPLATE)
141 | expect(mock_installer).to have_received(:install_template)
142 | end
143 |
144 | it 'should clear previously downloaded catalogs' do
145 | rambafile = {
146 | Generamba::TEMPLATES_KEY => [
147 | {
148 | Generamba::TEMPLATE_DECLARATION_NAME_KEY => 'test'
149 | }
150 | ]
151 | }
152 | downloader = instance_double('Generamba::CatalogDownloader')
153 | allow(downloader).to receive(:download_catalog)
154 |
155 | mock_installer = instance_double('Generamba::CatalogInstaller')
156 | allow(mock_installer).to receive(:install_template)
157 | installer_factory = instance_double('Generamba::TemplateInstallerFactory')
158 | allow(installer_factory).to receive(:installer_for_type).and_return(mock_installer)
159 |
160 | FakeFS do
161 | catalogs_path = Pathname.new(ENV['HOME'])
162 | .join(Generamba::GENERAMBA_HOME_DIR)
163 | .join(Generamba::CATALOGS_DIR)
164 | custom_catalog_path = catalogs_path.join('custom-catalog')
165 | FileUtils.mkdir_p(custom_catalog_path)
166 |
167 | processor = Generamba::TemplateProcessor.new(downloader, installer_factory)
168 | processor.install_templates(rambafile)
169 | result = custom_catalog_path.exist?
170 |
171 | expect(result).to eq(false)
172 | end
173 | end
174 | end
175 | end
176 |
--------------------------------------------------------------------------------
/spec/xcodeproj_helper_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative 'spec_helper'
2 |
3 | describe 'XcodeprojHelper' do
4 | describe 'method add_file_to_target?' do
5 | it 'should return true for Swift file' do
6 | filename = 'Test.swift'
7 | result = Generamba::XcodeprojHelper::is_compile_source?(filename)
8 | expect(result).to eq(true)
9 | end
10 |
11 | it 'should return true for Obj-C file' do
12 | filename = 'Test.m'
13 | result = Generamba::XcodeprojHelper::is_compile_source?(filename)
14 | expect(result).to eq(true)
15 | end
16 |
17 | it 'should return true for C++ file' do
18 | filename = 'Test.mm'
19 | result = Generamba::XcodeprojHelper::is_compile_source?(filename)
20 | expect(result).to eq(true)
21 | end
22 | end
23 |
24 | describe 'method add_file_to_bundle_resources?' do
25 | it 'should return true for Xib file' do
26 | resource_name = 'Test.xib'
27 | result = Generamba::XcodeprojHelper::is_bundle_resource?(resource_name)
28 | expect(result).to eq(true)
29 | end
30 |
31 | it 'should return true for Storyboard file' do
32 | resource_name = 'Test.storyboard'
33 | result = Generamba::XcodeprojHelper::is_bundle_resource?(resource_name)
34 | expect(result).to eq(true)
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------