generamba 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +64 -0
- data/LICENSE.txt +21 -0
- data/Rakefile +6 -0
- data/Readme.md +51 -0
- data/bin/GenerambaSandbox/Rambafile +17 -0
- data/bin/console +14 -0
- data/bin/generamba +5 -0
- data/bin/setup +7 -0
- data/generamba.gemspec +31 -0
- data/lib/generamba.rb +17 -0
- data/lib/generamba/cli/cli.rb +15 -0
- data/lib/generamba/cli/gen_command.rb +26 -0
- data/lib/generamba/cli/setup_command.rb +80 -0
- data/lib/generamba/cli/template/template_create_command.rb +29 -0
- data/lib/generamba/cli/template/template_group.rb +12 -0
- data/lib/generamba/cli/template/template_install_command.rb +10 -0
- data/lib/generamba/cli/thor_extension.rb +34 -0
- data/lib/generamba/code_generation/Rambafile.liquid +37 -0
- data/lib/generamba/code_generation/code_module.rb +32 -0
- data/lib/generamba/code_generation/content_generator.rb +42 -0
- data/lib/generamba/code_generation/module_template.rb +20 -0
- data/lib/generamba/code_generation/rambafile_generator.rb +22 -0
- data/lib/generamba/configuration/project_configuration.rb +9 -0
- data/lib/generamba/configuration/user_preferences.rb +50 -0
- data/lib/generamba/constants/constants.rb +12 -0
- data/lib/generamba/constants/rambafile_constants.rb +24 -0
- data/lib/generamba/constants/rambaspec_constants.rb +16 -0
- data/lib/generamba/constants/user_preferences_constants.rb +5 -0
- data/lib/generamba/helpers/template_helper.rb +32 -0
- data/lib/generamba/helpers/xcodeproj_helper.rb +87 -0
- data/lib/generamba/module_generator.rb +97 -0
- data/lib/generamba/template/creator/new_template/Code/Service/service.h.liquid +11 -0
- data/lib/generamba/template/creator/new_template/Code/Service/service.m.liquid +13 -0
- data/lib/generamba/template/creator/new_template/Tests/Service/service_tests.m.liquid +35 -0
- data/lib/generamba/template/creator/new_template/template.rambaspec.liquid +20 -0
- data/lib/generamba/template/creator/template_creator.rb +38 -0
- data/lib/generamba/template/helpers/rambaspec_validator.rb +47 -0
- data/lib/generamba/template/installer/abstract_installer.rb +9 -0
- data/lib/generamba/template/installer/catalog_installer.rb +40 -0
- data/lib/generamba/template/installer/local_installer.rb +32 -0
- data/lib/generamba/template/installer/remote_installer.rb +43 -0
- data/lib/generamba/template/processor/template_declaration.rb +34 -0
- data/lib/generamba/template/processor/template_processor.rb +77 -0
- data/lib/generamba/version.rb +3 -0
- metadata +221 -0
@@ -0,0 +1,10 @@
|
|
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
|
+
template_processor = Generamba::TemplateProcessor.new
|
7
|
+
template_processor.install_templates
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,34 @@
|
|
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
|
+
break if is_valid_value.call(value)
|
29
|
+
puts(description)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
### Headers settings
|
2
|
+
company: {{ company }}
|
3
|
+
|
4
|
+
### Xcode project settings
|
5
|
+
project_name: {{ project_name }}
|
6
|
+
prefix: {{ prefix }}
|
7
|
+
xcodeproj_path: {{ xcodeproj_path }}
|
8
|
+
|
9
|
+
### Code generation settings section
|
10
|
+
# The main project target name
|
11
|
+
project_target: {{ project_target }}
|
12
|
+
|
13
|
+
# The file path for new modules
|
14
|
+
project_file_path: {{ project_file_path }}
|
15
|
+
|
16
|
+
# The Xcode group path to new modules
|
17
|
+
project_group_path: {{ project_group_path }}
|
18
|
+
|
19
|
+
### Tests generation settings section
|
20
|
+
# The tests target name
|
21
|
+
test_target: {{ test_target }}
|
22
|
+
|
23
|
+
# The file path for new tests
|
24
|
+
test_file_path: {{ test_file_path }}
|
25
|
+
|
26
|
+
# The Xcode group path to new tests
|
27
|
+
test_group_path: {{ test_group_path }}
|
28
|
+
|
29
|
+
### Dependencies settings section
|
30
|
+
podfile_path: {{ podfile_path }}
|
31
|
+
cartfile_path: {{ cartfile_path }}
|
32
|
+
|
33
|
+
### Templates
|
34
|
+
templates:
|
35
|
+
#- {name: local_template_name, path: absolute/file/path}
|
36
|
+
#- {name: remote_template_name, git: https://github.com/igrekde/remote_template}
|
37
|
+
#- {name: catalog_template_name}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Generamba
|
2
|
+
|
3
|
+
# Represents currently generating code module
|
4
|
+
class CodeModule
|
5
|
+
attr_reader :name, :description, :author, :company, :year, :prefix, :project_name
|
6
|
+
|
7
|
+
def initialize(name, description)
|
8
|
+
@name = name
|
9
|
+
@description = description
|
10
|
+
end
|
11
|
+
|
12
|
+
def author
|
13
|
+
Generamba::UserPreferences.obtain_username
|
14
|
+
end
|
15
|
+
|
16
|
+
def company
|
17
|
+
ProjectConfiguration.company
|
18
|
+
end
|
19
|
+
|
20
|
+
def year
|
21
|
+
Time.now.year.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def prefix
|
25
|
+
ProjectConfiguration.prefix
|
26
|
+
end
|
27
|
+
|
28
|
+
def project_name
|
29
|
+
ProjectConfiguration.project_name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'liquid'
|
2
|
+
require 'tilt'
|
3
|
+
|
4
|
+
module Generamba
|
5
|
+
|
6
|
+
# Responsible for generating code using provided liquid templates
|
7
|
+
class ContentGenerator
|
8
|
+
|
9
|
+
# Generates and returns a body of a specific code file.
|
10
|
+
# @param file []Hash<String,String>] A hashmap with template's filename and filepath
|
11
|
+
# @param code_module [CodeModule] The model describing a generating module
|
12
|
+
# @param template [ModuleTemplate] The model describing a Generamba template used for code generation
|
13
|
+
#
|
14
|
+
# @return [String] The generated body
|
15
|
+
def self.create_file_content(file, code_module, template)
|
16
|
+
file_template = Tilt.new(template.template_path.join(file[TEMPLATE_FILE_PATH_KEY]))
|
17
|
+
file_name = File.basename(file[TEMPLATE_FILE_NAME_KEY])
|
18
|
+
module_info = {
|
19
|
+
'name' => code_module.name,
|
20
|
+
'file_name' => file_name,
|
21
|
+
'description' => code_module.description,
|
22
|
+
'project_name' => code_module.project_name
|
23
|
+
}
|
24
|
+
|
25
|
+
developer = {
|
26
|
+
'name' => code_module.author,
|
27
|
+
'company' => code_module.company
|
28
|
+
}
|
29
|
+
|
30
|
+
scope = {
|
31
|
+
'year' => code_module.year,
|
32
|
+
'date' => Time.now.strftime('%d/%m/%Y'),
|
33
|
+
'developer' => developer,
|
34
|
+
'module_info' => module_info,
|
35
|
+
'prefix' => code_module.prefix
|
36
|
+
}
|
37
|
+
|
38
|
+
output = file_template.render(scope)
|
39
|
+
return output
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'generamba/helpers/template_helper.rb'
|
2
|
+
require 'settingslogic'
|
3
|
+
|
4
|
+
module Generamba
|
5
|
+
|
6
|
+
# Represents a single Generamba module template
|
7
|
+
class ModuleTemplate
|
8
|
+
attr_reader :template_name, :template_path, :code_files, :test_files
|
9
|
+
|
10
|
+
def initialize(name)
|
11
|
+
spec_path = TemplateHelper.obtain_spec(name)
|
12
|
+
spec = Settingslogic.new(spec_path)
|
13
|
+
|
14
|
+
@code_files = spec[TEMPLATE_CODE_FILES_KEY]
|
15
|
+
@test_files = spec[TEMPLATE_TEST_FILES_KEY]
|
16
|
+
@template_name = spec.name
|
17
|
+
@template_path = TemplateHelper.obtain_path(name)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'liquid'
|
2
|
+
require 'tilt'
|
3
|
+
|
4
|
+
module Generamba
|
5
|
+
|
6
|
+
# Responsible for creating Generamba configs
|
7
|
+
class RambafileGenerator
|
8
|
+
|
9
|
+
# Creates a Rambafile using the provided properties hashmap
|
10
|
+
# @param properties Rambafile properties
|
11
|
+
#
|
12
|
+
# @return void
|
13
|
+
def self.create_rambafile(properties)
|
14
|
+
template = Tilt.new(File.dirname(__FILE__) + '/Rambafile.liquid')
|
15
|
+
output = template.render(properties)
|
16
|
+
|
17
|
+
File.open(RAMBAFILE_NAME, 'w+') {|f|
|
18
|
+
f.write(output)
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,50 @@
|
|
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
|
+
if path_exists == false
|
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
|
+
if preferences_exist == false
|
44
|
+
File.open(preferences_path, 'w+') { |f| f.write('') }
|
45
|
+
end
|
46
|
+
|
47
|
+
return preferences_path
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,12 @@
|
|
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-ios/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
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Generamba
|
2
|
+
|
3
|
+
# Keys of Rambafile files
|
4
|
+
COMPANY_KEY = 'company'
|
5
|
+
PROJECT_NAME_KEY = 'project_name'
|
6
|
+
PROJECT_PREFIX_KEY = 'prefix'
|
7
|
+
XCODEPROJ_PATH_KEY = 'xcodeproj_path'
|
8
|
+
|
9
|
+
PROJECT_TARGET_KEY = 'project_target'
|
10
|
+
PROJECT_FILE_PATH_KEY = 'project_file_path'
|
11
|
+
PROJECT_GROUP_PATH_KEY = 'project_group_path'
|
12
|
+
|
13
|
+
TEST_TARGET_KEY = 'test_target'
|
14
|
+
TEST_FILE_PATH_KEY = 'test_file_path'
|
15
|
+
TEST_GROUP_PATH_KEY = 'test_group_path'
|
16
|
+
|
17
|
+
PODFILE_PATH_KEY = 'podfile_path'
|
18
|
+
CARTFILE_PATH_KEY = 'cartfile_path'
|
19
|
+
|
20
|
+
TEMPLATES_KEY = 'templates'
|
21
|
+
TEMPLATE_DECLARATION_NAME_KEY = 'name'
|
22
|
+
TEMPLATE_DECLARATION_LOCAL_KEY = 'local'
|
23
|
+
TEMPLATE_DECLARATION_GIT_KEY = 'git'
|
24
|
+
end
|
@@ -0,0 +1,16 @@
|
|
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_PATH_KEY = 'path'
|
14
|
+
|
15
|
+
TEMPLATE_DEPENDENCIES_KEY = 'dependencies'
|
16
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Generamba
|
2
|
+
|
3
|
+
# Provides a number of helper methods for manipulating Generamba template files
|
4
|
+
class TemplateHelper
|
5
|
+
|
6
|
+
# Returns a file path for a specific template .rambaspec file
|
7
|
+
# @param template_name [String] The Generamba template name
|
8
|
+
#
|
9
|
+
# @return [Pathname]
|
10
|
+
def self.obtain_spec(template_name)
|
11
|
+
template_path = self.obtain_path(template_name)
|
12
|
+
spec_path = template_path.join(template_name + RAMBASPEC_EXTENSION)
|
13
|
+
|
14
|
+
return spec_path
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns a file path for a specific template folder
|
18
|
+
# @param template_name [String] The Generamba template name
|
19
|
+
#
|
20
|
+
# @return [Pathname]
|
21
|
+
def self.obtain_path(template_name)
|
22
|
+
path = Pathname.new(Dir.getwd)
|
23
|
+
.join(TEMPLATES_FOLDER)
|
24
|
+
.join(template_name)
|
25
|
+
|
26
|
+
error_description = "Cannot find #{template_name}! Add it to the Rambafile and run *generamba template install*"
|
27
|
+
raise StandardError.new(error_description) if path.exist? == false
|
28
|
+
|
29
|
+
return path
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Generamba
|
2
|
+
|
3
|
+
# Provides a number of helper methods for working with xcodeproj gem
|
4
|
+
class XcodeprojHelper
|
5
|
+
|
6
|
+
# Returns a PBXProject class for a given name
|
7
|
+
# @param project_name [String] The name of the project file
|
8
|
+
#
|
9
|
+
# @return [Xcodeproj::Project]
|
10
|
+
def self.obtain_project(project_name)
|
11
|
+
Xcodeproj::Project.open(project_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns an AbstractTarget class for a given name
|
15
|
+
# @param target_name [String] The name of the target
|
16
|
+
# @param project [Xcodeproj::Project] The target xcodeproj file
|
17
|
+
#
|
18
|
+
# @return [Xcodeproj::AbstractTarget]
|
19
|
+
def self.obtain_target(target_name, project)
|
20
|
+
project.targets.each { |target|
|
21
|
+
if target.name == target_name
|
22
|
+
return target
|
23
|
+
end
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
# Adds a provided file to a specific Project and Target
|
28
|
+
# @param project [Xcodeproj::Project] The target xcodeproj file
|
29
|
+
# @param target [AbstractTarget] The target for a file
|
30
|
+
# @param group_path [Pathname] The Xcode group path for current file
|
31
|
+
# @param file_path [Pathname] The file path for current file
|
32
|
+
#
|
33
|
+
# @return [void]
|
34
|
+
def self.add_file_to_project_and_target(project, target, group_path, file_path)
|
35
|
+
module_group = self.retreive_or_create_group(group_path, project)
|
36
|
+
xcode_file = module_group.new_file(File.absolute_path(file_path))
|
37
|
+
|
38
|
+
file_name = File.basename(file_path)
|
39
|
+
if File.extname(file_name) == '.m'
|
40
|
+
target.add_file_references([xcode_file])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Recursively clears children of te given group
|
45
|
+
# @param project [Xcodeproj::Project] The working Xcode project file
|
46
|
+
# @param group_path [Pathname] The full group path
|
47
|
+
#
|
48
|
+
# @return [Void]
|
49
|
+
def self.clear_group(project, group_path)
|
50
|
+
module_group = self.retreive_or_create_group(group_path, project)
|
51
|
+
module_group.clear
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
# Finds or creates a group in a xcodeproj file with a given path
|
57
|
+
# @param group_path [Pathname] The full group path
|
58
|
+
# @param project [Xcodeproj::Project] The working Xcode project file
|
59
|
+
#
|
60
|
+
# @return [PBXGroup]
|
61
|
+
def self.retreive_or_create_group(group_path, project)
|
62
|
+
group_names = group_names_from_group_path(group_path)
|
63
|
+
|
64
|
+
final_group = project
|
65
|
+
|
66
|
+
group_names.each do |group_name|
|
67
|
+
next_group = final_group[group_name]
|
68
|
+
if (next_group == nil)
|
69
|
+
next_group = final_group.new_group(group_name)
|
70
|
+
end
|
71
|
+
|
72
|
+
final_group = next_group
|
73
|
+
end
|
74
|
+
|
75
|
+
return final_group
|
76
|
+
end
|
77
|
+
|
78
|
+
# Splits the provided Xcode group path to an array of separate groups
|
79
|
+
# @param group_path The full group path
|
80
|
+
#
|
81
|
+
# @return [[String]]
|
82
|
+
def self.group_names_from_group_path(group_path)
|
83
|
+
groups = group_path.to_s.split('/')
|
84
|
+
return groups
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|