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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +4 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +64 -0
  6. data/LICENSE.txt +21 -0
  7. data/Rakefile +6 -0
  8. data/Readme.md +51 -0
  9. data/bin/GenerambaSandbox/Rambafile +17 -0
  10. data/bin/console +14 -0
  11. data/bin/generamba +5 -0
  12. data/bin/setup +7 -0
  13. data/generamba.gemspec +31 -0
  14. data/lib/generamba.rb +17 -0
  15. data/lib/generamba/cli/cli.rb +15 -0
  16. data/lib/generamba/cli/gen_command.rb +26 -0
  17. data/lib/generamba/cli/setup_command.rb +80 -0
  18. data/lib/generamba/cli/template/template_create_command.rb +29 -0
  19. data/lib/generamba/cli/template/template_group.rb +12 -0
  20. data/lib/generamba/cli/template/template_install_command.rb +10 -0
  21. data/lib/generamba/cli/thor_extension.rb +34 -0
  22. data/lib/generamba/code_generation/Rambafile.liquid +37 -0
  23. data/lib/generamba/code_generation/code_module.rb +32 -0
  24. data/lib/generamba/code_generation/content_generator.rb +42 -0
  25. data/lib/generamba/code_generation/module_template.rb +20 -0
  26. data/lib/generamba/code_generation/rambafile_generator.rb +22 -0
  27. data/lib/generamba/configuration/project_configuration.rb +9 -0
  28. data/lib/generamba/configuration/user_preferences.rb +50 -0
  29. data/lib/generamba/constants/constants.rb +12 -0
  30. data/lib/generamba/constants/rambafile_constants.rb +24 -0
  31. data/lib/generamba/constants/rambaspec_constants.rb +16 -0
  32. data/lib/generamba/constants/user_preferences_constants.rb +5 -0
  33. data/lib/generamba/helpers/template_helper.rb +32 -0
  34. data/lib/generamba/helpers/xcodeproj_helper.rb +87 -0
  35. data/lib/generamba/module_generator.rb +97 -0
  36. data/lib/generamba/template/creator/new_template/Code/Service/service.h.liquid +11 -0
  37. data/lib/generamba/template/creator/new_template/Code/Service/service.m.liquid +13 -0
  38. data/lib/generamba/template/creator/new_template/Tests/Service/service_tests.m.liquid +35 -0
  39. data/lib/generamba/template/creator/new_template/template.rambaspec.liquid +20 -0
  40. data/lib/generamba/template/creator/template_creator.rb +38 -0
  41. data/lib/generamba/template/helpers/rambaspec_validator.rb +47 -0
  42. data/lib/generamba/template/installer/abstract_installer.rb +9 -0
  43. data/lib/generamba/template/installer/catalog_installer.rb +40 -0
  44. data/lib/generamba/template/installer/local_installer.rb +32 -0
  45. data/lib/generamba/template/installer/remote_installer.rb +43 -0
  46. data/lib/generamba/template/processor/template_declaration.rb +34 -0
  47. data/lib/generamba/template/processor/template_processor.rb +77 -0
  48. data/lib/generamba/version.rb +3 -0
  49. 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,9 @@
1
+ require 'settingslogic'
2
+
3
+ module Generamba
4
+
5
+ # A singletone class representing a Rambafile of the current project
6
+ class ProjectConfiguration < Settingslogic
7
+ source Dir.getwd + '/' + RAMBAFILE_NAME
8
+ end
9
+ 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,5 @@
1
+ module Generamba
2
+
3
+ # Keys of file user_preferences.yml
4
+ USERNAME_KEY = 'username'
5
+ 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