generamba 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|