nabokov 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +1 -0
  3. data/.gitignore +43 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +113 -0
  6. data/.travis.yml +14 -0
  7. data/CHANGELOG.md +5 -0
  8. data/Gemfile +9 -0
  9. data/LICENSE +21 -0
  10. data/README.md +16 -0
  11. data/Rakefile +22 -0
  12. data/bin/nabokov +5 -0
  13. data/lib/nabokov/commands/runner.rb +22 -0
  14. data/lib/nabokov/commands/setup.rb +75 -0
  15. data/lib/nabokov/commands/syncers/localizations_repo_syncer.rb +101 -0
  16. data/lib/nabokov/commands/syncers/project_syncer.rb +106 -0
  17. data/lib/nabokov/commands/syncers/syncer.rb +68 -0
  18. data/lib/nabokov/core/file_manager.rb +36 -0
  19. data/lib/nabokov/core/nabokovfile.rb +66 -0
  20. data/lib/nabokov/core/nabokovfile_content_validator.rb +51 -0
  21. data/lib/nabokov/core/nabokovfile_keys.rb +34 -0
  22. data/lib/nabokov/git/git_repo.rb +137 -0
  23. data/lib/nabokov/helpers/informator.rb +83 -0
  24. data/lib/nabokov/helpers/merger.rb +86 -0
  25. data/lib/nabokov/models/strings_file.rb +7 -0
  26. data/lib/nabokov/version.rb +8 -0
  27. data/lib/nabokov.rb +14 -0
  28. data/nabokov.gemspec +31 -0
  29. data/spec/fixtures/.DS_Store +0 -0
  30. data/spec/fixtures/README.md +1 -0
  31. data/spec/fixtures/de.strings +1 -0
  32. data/spec/fixtures/en.strings +1 -0
  33. data/spec/fixtures/nabokovfile_example.yaml +9 -0
  34. data/spec/fixtures/nabokovfile_example_invalid.yaml +2 -0
  35. data/spec/fixtures/nabokovfile_example_without_master_branch.yaml +8 -0
  36. data/spec/fixtures/test_git_setup/existed_pre_commit_file +0 -0
  37. data/spec/fixtures/test_git_setup/existed_pre_commit_file_alias +0 -0
  38. data/spec/fixtures/test_git_setup/not_executable_pre_commit_file +0 -0
  39. data/spec/fixtures/test_localizations_repo_syncer/localizations_repo_fixtures/README.md +1 -0
  40. data/spec/fixtures/test_localizations_repo_syncer/nabokovfile.yaml +8 -0
  41. data/spec/fixtures/test_project_syncer/localizations_repo_fixtures/de.strings +2 -0
  42. data/spec/fixtures/test_project_syncer/localizations_repo_fixtures/en.strings +2 -0
  43. data/spec/fixtures/test_project_syncer/project_repo_fixtures/de.strings +2 -0
  44. data/spec/fixtures/test_project_syncer/project_repo_fixtures/en.strings +2 -0
  45. data/spec/fixtures/test_project_syncer/project_repo_fixtures/nabokovfile.yaml +9 -0
  46. data/spec/lib/nabokov/commands/localizations_repo_syncer_spec.rb +137 -0
  47. data/spec/lib/nabokov/commands/project_syncer_spec.rb +61 -0
  48. data/spec/lib/nabokov/commands/runner_spec.rb +7 -0
  49. data/spec/lib/nabokov/commands/setup_spec.rb +101 -0
  50. data/spec/lib/nabokov/commands/syncer_spec.rb +23 -0
  51. data/spec/lib/nabokov/core/file_manager_spec.rb +115 -0
  52. data/spec/lib/nabokov/core/nabokovfile_content_validator_spec.rb +155 -0
  53. data/spec/lib/nabokov/core/nabokovfile_keyes_spec.rb +31 -0
  54. data/spec/lib/nabokov/core/nabokovfile_spec.rb +53 -0
  55. data/spec/lib/nabokov/git/git_repo_spec.rb +670 -0
  56. data/spec/lib/nabokov/helpers/informator_spec.rb +49 -0
  57. data/spec/lib/nabokov/helpers/merger_spec.rb +114 -0
  58. data/spec/lib/nabokov/models/strings_file_spec.rb +7 -0
  59. data/spec/spec_helper.rb +11 -0
  60. metadata +238 -0
@@ -0,0 +1,66 @@
1
+ require "yaml"
2
+ require "uri"
3
+ require "nabokov/core/nabokovfile_keys"
4
+ require "nabokov/core/nabokovfile_content_validator"
5
+
6
+ module Nabokov
7
+ # Class represents the nabokovfile with the settings for nabokov
8
+ class Nabokovfile
9
+ # @return [String] The localizations repo url string
10
+ attr_accessor :localizations_repo_url
11
+ # @return [String] The localizations repo master branch
12
+ attr_accessor :localizations_repo_master_branch
13
+ # @return [String] The localizations repo local path
14
+ attr_accessor :localizations_repo_local_path
15
+ # @return [Hash] The Hash with key as localization name and value as repspected localization file path
16
+ attr_accessor :project_localization_file_paths
17
+ # @return [String] The project repo local path
18
+ attr_accessor :project_local_path
19
+
20
+ def initialize(path)
21
+ raise "Path is a required parameter" if path.nil?
22
+ raise "Couldn't find nabokov file at '#{path}'" unless File.exist?(path)
23
+ nabokovfile = File.read(path)
24
+ yaml_data = read_data_from_yaml_file(nabokovfile, path)
25
+ validate_content(yaml_data)
26
+ read_content(yaml_data)
27
+ end
28
+
29
+ def localizations_repo_local_path
30
+ return @localizations_repo_local_path unless @localizations_repo_local_path.nil?
31
+ @localizations_repo_local_path ||= ""
32
+ end
33
+
34
+ private
35
+
36
+ def read_data_from_yaml_file(yaml_file, path)
37
+ YAML.load(yaml_file)
38
+ rescue Psych::SyntaxError
39
+ raise "File at '#{path}' doesn't have a legit YAML syntax"
40
+ end
41
+
42
+ def validate_content(content_hash)
43
+ validator = NabokovfileContentValidator.new(content_hash)
44
+ validator.validate
45
+ end
46
+
47
+ def read_content(content_hash)
48
+ localizations_repo = content_hash[NabokovfileKeyes.localizations_repo]
49
+ self.localizations_repo_url = localizations_repo[NabokovfileKeyes.localizations_repo_url]
50
+ self.localizations_repo_master_branch = localizations_repo[NabokovfileKeyes.localizations_repo_master_branch].nil? ? "master" : localizations_repo[NabokovfileKeyes.localizations_repo_master_branch]
51
+ project_repo = content_hash[NabokovfileKeyes.project_repo]
52
+ self.project_localization_file_paths = project_repo[NabokovfileKeyes.project_localization_file_paths]
53
+ self.project_local_path = project_repo[NabokovfileKeyes.project_local_path]
54
+ self.localizations_repo_local_path = build_localization_local_path
55
+ end
56
+
57
+ def build_localization_local_path
58
+ repo_url_path = URI(self.localizations_repo_url).path.to_s
59
+ home_dir = Dir.home.to_s
60
+ repo_url_name_without_extension = File.basename(repo_url_path, File.extname(repo_url_path)).downcase
61
+ repo_url_organization = File.dirname(repo_url_path).downcase
62
+ nabokov_dir_name = "/.nabokov"
63
+ home_dir + nabokov_dir_name + repo_url_organization + "/" + repo_url_name_without_extension
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,51 @@
1
+ require "uri"
2
+ require "nabokov/core/nabokovfile_keys"
3
+
4
+ module Nabokov
5
+ # This class is responsible for nabokovfile content validation
6
+ # The validation rules are for localizations_repo and project_repo settings
7
+ class NabokovfileContentValidator
8
+ attr_accessor :nabokovfile_hash
9
+
10
+ def initialize(nabokovfile_hash)
11
+ self.nabokovfile_hash = nabokovfile_hash
12
+ end
13
+
14
+ # Performs validation
15
+ # First rule: localizations_repo should be the type of Hash
16
+ # localizations_repo_url should be valid URL with secure https scheme
17
+ # Second rule: project_repo should be the type of Hash
18
+ # project localizations_key should be the of Hash
19
+ # project_localization_file_paths should point to existed files
20
+ # project_local_path should point to valid folder
21
+ def validate
22
+ validate_localizations_repo
23
+ validate_project_repo
24
+ end
25
+
26
+ private
27
+
28
+ def validate_localizations_repo
29
+ localizations_repo = self.nabokovfile_hash[NabokovfileKeyes.localizations_repo]
30
+ raise "Localizations repo must be a type of Hash" unless localizations_repo.kind_of?(Hash)
31
+
32
+ url = localizations_repo[NabokovfileKeyes.localizations_repo_url]
33
+ raise "'#{url}' is not a valid URL" unless url =~ URI.regexp
34
+ raise "Please use 'https://...' instead of '#{url}' only supports encrypted requests" unless url.start_with?("https://")
35
+ end
36
+
37
+ def validate_project_repo
38
+ project_repo = self.nabokovfile_hash[NabokovfileKeyes.project_repo]
39
+ raise "Project repo must be a type of Hash" unless project_repo.kind_of?(Hash)
40
+
41
+ localizations_key = NabokovfileKeyes.project_localization_file_paths
42
+ localizations = project_repo[localizations_key]
43
+ raise "Localizations must be a type of Hash" unless localizations.kind_of?(Hash)
44
+ localizations.each_value { |path| raise "Couldn't find strings file at '#{path}'" unless File.exist?(path) }
45
+
46
+ project_local_path_key = NabokovfileKeyes.project_local_path
47
+ project_local_path = project_repo[project_local_path_key]
48
+ raise "Project repo local path must be presented" if project_local_path.nil?
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,34 @@
1
+ module Nabokov
2
+ # Class contains the named constants for nabokovfile keyes
3
+ class NabokovfileKeyes
4
+ # @return [String] The key to get the localizations repo settings
5
+ def self.localizations_repo
6
+ return "localizations_repo"
7
+ end
8
+
9
+ # @return [String] The key to get the localizations remote URL string
10
+ def self.localizations_repo_url
11
+ return "url"
12
+ end
13
+
14
+ # @return [String] The key to get the master branch of the localizations repo
15
+ def self.localizations_repo_master_branch
16
+ return "master_branch"
17
+ end
18
+
19
+ # @return [String] The key to get the project repo settings
20
+ def self.project_repo
21
+ return "project_repo"
22
+ end
23
+
24
+ # @return [String] The key to get the (localization_code => localization_file_path) hash
25
+ def self.project_localization_file_paths
26
+ return "localizations"
27
+ end
28
+
29
+ # @return [String] The key to get the project's local path
30
+ def self.project_local_path
31
+ return "local_path"
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,137 @@
1
+ require "git"
2
+ require "uri"
3
+ require "securerandom"
4
+ require "pathname"
5
+
6
+ module Nabokov
7
+ # This class is basically the wrapper aroung the ruby-git gem
8
+ # Note: the ruby gem is taken not from gem spec repo, but from https://github.com/Antondomashnev/ruby-git
9
+ class GitRepo
10
+ # @return [String] Repo's remote URL, could be nil
11
+ attr_accessor :remote_url
12
+ # @return [String] Local path to the repo
13
+ attr_accessor :local_path
14
+ # @return [Git::Base] Underlying git repo
15
+ attr_reader :git_repo
16
+
17
+ def initialize(local_path, remote_url = nil, git_repo = nil)
18
+ raise "local_path is a required parameter" if local_path.nil?
19
+ expanded_local_path = File.expand_path(local_path)
20
+ @local_pathname = Pathname.new(expanded_local_path)
21
+ @git_repo = git_repo
22
+ self.remote_url = remote_url
23
+ self.local_path = expanded_local_path
24
+ end
25
+
26
+ def clone
27
+ raise "Git repo has been already cloned at '#{self.local_path}', please use 'init' instead" if repo_exist_at_local_path
28
+ @git_repo ||= Git.clone(self.remote_url, @local_pathname.basename.to_s, path: @local_pathname.parent.to_s)
29
+ end
30
+
31
+ def init
32
+ raise "Git repo has not been cloned yet from '#{self.remote_url}', please use 'clone' instead" unless repo_exist_at_local_path
33
+ @git_repo ||= Git.init(self.local_path)
34
+ end
35
+
36
+ def add(file_path)
37
+ raise "Could not find any file to add at path '#{file_path}'" unless File.exist?(file_path)
38
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before adding new files to the index" if @git_repo.nil?
39
+ @git_repo.add(file_path)
40
+ end
41
+
42
+ def commit(message = nil)
43
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before commiting new files" if @git_repo.nil?
44
+ message ||= "Automatic commit by nabokov"
45
+ @git_repo.commit(message)
46
+ end
47
+
48
+ def push
49
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before pushing any changes to remote" if @git_repo.nil?
50
+ @git_repo.push
51
+ end
52
+
53
+ def pull
54
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before pushing any changes to remote" if @git_repo.nil?
55
+ @git_repo.pull
56
+ end
57
+
58
+ def checkout_branch(name)
59
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before checkouting any branch" if @git_repo.nil?
60
+ raise "branch name could not be nil or zero length" if name.nil? || name.length.zero?
61
+ if @git_repo.is_branch?(name)
62
+ @git_repo.checkout(name)
63
+ else
64
+ @git_repo.checkout(name, { new_branch: true })
65
+ end
66
+ end
67
+
68
+ def delete_branch(name)
69
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before deleting any branch" if @git_repo.nil?
70
+ raise "branch name could not be nil or zero length" if name.nil? || name.length.zero?
71
+ @git_repo.branch(name).delete
72
+ end
73
+
74
+ def merge_branches(original_branch, branch_to_be_merged)
75
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before merging any branches" if @git_repo.nil?
76
+ raise "original branch name could not be nil or zero length" if original_branch.nil? || original_branch.length.zero?
77
+ raise "branch to be merged in name could not be nil or zero length" if branch_to_be_merged.nil? || branch_to_be_merged.length.zero?
78
+ @git_repo.branch(original_branch).merge(@git_repo.branch(branch_to_be_merged))
79
+ end
80
+
81
+ def changes?
82
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before checking if the git repo has changes" if @git_repo.nil?
83
+ return true if @git_repo.status.deleted.count > 0
84
+ return true if @git_repo.status.added.count > 0
85
+ return true if @git_repo.status.changed.count > 0
86
+ false
87
+ end
88
+
89
+ def unfinished_merge?
90
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before checking if the git repo has unfinished merge" if @git_repo.nil?
91
+ return @git_repo.has_unmerged_files?
92
+ end
93
+
94
+ def current_branch
95
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before getting the current branch" if @git_repo.nil?
96
+ return @git_repo.current_branch
97
+ end
98
+
99
+ def abort_merge
100
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before aborting merge" if @git_repo.nil?
101
+ raise "nothing to abort - git repo doesn't have unfinished merge" unless self.unfinished_merge?
102
+ @git_repo.abort_merge
103
+ end
104
+
105
+ def unmerged_files
106
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before asking for unmerged files" if @git_repo.nil?
107
+ return [] unless @git_repo.has_unmerged_files?
108
+ conflicted_files = []
109
+ @git_repo.each_conflict do |file, your_version, their_version|
110
+ conflicted_files << file
111
+ end
112
+ conflicted_files
113
+ end
114
+
115
+ def reset_to_commit(commit_sha, options = {})
116
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before resetting" if @git_repo.nil?
117
+ raise "'commit' is a required parameter and could not be nil" if commit_sha.nil?
118
+ if options[:hard]
119
+ @git_repo.reset_hard(commit_sha)
120
+ else
121
+ @git_repo.reset(commit_sha)
122
+ end
123
+ end
124
+
125
+ def log(number_of_commits)
126
+ raise "'git' is not initialized yet, please call either 'clone' or 'init' before getting the log" if @git_repo.nil?
127
+ commits = @git_repo.log(number_of_commits)
128
+ commits.map(&:sha)
129
+ end
130
+
131
+ private
132
+
133
+ def repo_exist_at_local_path
134
+ Dir.exist?(self.local_path)
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,83 @@
1
+ require "cork"
2
+
3
+ module Nabokov
4
+ # This class is heavily based on the Interviewer class from the Danger gem
5
+ # The original link is https://github.com/danger/danger/blob/master/lib/danger/commands/init_helpers/interviewer.rb
6
+ class Informator
7
+ attr_accessor :no_waiting, :ui
8
+
9
+ def initialize(cork_board)
10
+ @ui = cork_board
11
+ end
12
+
13
+ def show_prompt
14
+ ui.print("> ".bold.green)
15
+ end
16
+
17
+ def say(message)
18
+ ui.puts(message)
19
+ end
20
+
21
+ def inform(message)
22
+ ui.puts(message.green)
23
+ end
24
+
25
+ def important(message)
26
+ i = message.length + 8
27
+ inform("-" * i)
28
+ inform("--- " + message + " ---")
29
+ inform("-" * i)
30
+ end
31
+
32
+ def warn(message)
33
+ ui.puts(message.yellow)
34
+ end
35
+
36
+ def error(message)
37
+ ui.puts(message.red)
38
+ end
39
+
40
+ def wait_for_return
41
+ STDOUT.flush
42
+ STDIN.gets unless @no_waiting
43
+ ui.puts
44
+ end
45
+
46
+ def ask_with_answers(question, possible_answers)
47
+ ui.print("\n#{question}? [")
48
+
49
+ print_info = proc do
50
+ possible_answers.each_with_index do |answer, i|
51
+ the_answer = i.zero? ? answer.underline : answer
52
+ ui.print " " + the_answer
53
+ ui.print(" /") if i != possible_answers.length - 1
54
+ end
55
+ ui.print " ]\n"
56
+ end
57
+ print_info.call
58
+
59
+ answer = ""
60
+
61
+ loop do
62
+ show_prompt
63
+ answer = @no_waiting ? possible_answers[0].downcase : STDIN.gets.downcase.chomp
64
+
65
+ answer = "yes" if answer == "y"
66
+ answer = "no" if answer == "n"
67
+
68
+ # default to first answer
69
+ if answer == ""
70
+ answer = possible_answers[0].downcase
71
+ ui.puts "Using: " + answer.yellow
72
+ end
73
+
74
+ break if possible_answers.map(&:downcase).include? answer
75
+
76
+ ui.print "\nPossible answers are ["
77
+ print_info.call
78
+ end
79
+
80
+ answer
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,86 @@
1
+ require "nabokov/git/git_repo"
2
+ require "nabokov/helpers/informator"
3
+
4
+ module Nabokov
5
+ # Result of the merge action perfomed by Nabokov::Merger
6
+ class MergerResult
7
+ SUCCEEDED = "succeeded".freeze
8
+ ABORTED = "aborted".freeze
9
+ end
10
+
11
+ # Class is responsible for merging two branches
12
+ class Merger
13
+ def initialize(informator, git_repo, rescue_commit_sha = nil)
14
+ raise "'informator' is a required parameter" if informator.nil?
15
+ raise "'git_repo' is a required parameter" if git_repo.nil?
16
+ @rescue_commit_sha = rescue_commit_sha
17
+ @git_repo = git_repo
18
+ @informator = informator
19
+ end
20
+
21
+ # Merges one branch with another branch
22
+ # It handles the situation when there are merge conflicts and provides
23
+ # the interface to the user to resolve the conflicts
24
+ def merge(head, branch)
25
+ @git_repo.merge_branches(head, branch)
26
+ MergerResult::SUCCEEDED
27
+ rescue Git::GitExecuteError
28
+ rescue_merge
29
+ end
30
+
31
+ private
32
+
33
+ def rescue_merge
34
+ ui.error("Merge failed with conflicts. Nabokov needs your help to continue")
35
+ proceed_option = ui.ask_with_answers("Would you like to resolve the conflicts manually or abort the synchronization?\n", ["resolve", "abort"])
36
+ if proceed_option == "abort"
37
+ abort_merge
38
+ elsif proceed_option == "resolve"
39
+ resolve_merge
40
+ end
41
+ end
42
+
43
+ def abort_merge
44
+ @git_repo.abort_merge
45
+ @git_repo.reset_to_commit(@rescue_commit_sha, { hard: true }) unless @rescue_commit_sha.nil?
46
+ MergerResult::ABORTED
47
+ end
48
+
49
+ def resolve_merge
50
+ ui.say("Great! Please resolve conflict in the following files:")
51
+ unmerged_files = @git_repo.unmerged_files
52
+ unmerged_files.each do |file|
53
+ file_path = @git_repo.local_path + "/" + file
54
+ ui.say("* #{file_path}")
55
+ end
56
+ ui.say("Please press return when you're ready to move on...")
57
+ ui.wait_for_return
58
+ commit_after_merge_resolving(unmerged_files)
59
+ MergerResult::SUCCEEDED
60
+ end
61
+
62
+ def commit_after_merge_resolving(merged_files)
63
+ commit_merge = proc do
64
+ merged_files.each do |file|
65
+ file_path = @git_repo.local_path + "/" + file
66
+ ui.say("Adding #{file_path} to git index...")
67
+ @git_repo.add(file_path)
68
+ end
69
+ ui.say("Commiting merge conflicts resolving...")
70
+ @git_repo.commit("Nabokov merge conflicts manually have been resolved...")
71
+ end
72
+
73
+ if @git_repo.changes?
74
+ commit_merge.call
75
+ else
76
+ ui.warn("Seems like you haven't resolved the merge, if you want to continue anyway please press return...")
77
+ ui.wait_for_return
78
+ commit_merge.call if @git_repo.changes?
79
+ end
80
+ end
81
+
82
+ def ui
83
+ @informator
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,7 @@
1
+ module Nabokov
2
+ class StringsFile
3
+ def self.extension
4
+ return "strings"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module Nabokov
2
+ VERSION = "0.1.0".freeze
3
+ DESCRIPTION = "One of the way to work on the localization - store it in the separate github repo
4
+ and asks localization team to update files in that repo.
5
+ This solution brings as well advantages but as well a disadvantages, to minimize the disadvantages
6
+ nabokov was invented. It helps developer to automatically keep remote localzation up to date and
7
+ also remain the project localization up to date as well.".freeze
8
+ end
data/lib/nabokov.rb ADDED
@@ -0,0 +1,14 @@
1
+ require "nabokov/version"
2
+ require "nabokov/core/nabokovfile"
3
+ require "nabokov/commands/runner"
4
+ require "nabokov/commands/syncers/syncer"
5
+ require "nabokov/commands/syncers/localizations_repo_syncer"
6
+ require "nabokov/commands/syncers/project_syncer"
7
+ require "nabokov/commands/setup"
8
+
9
+ require "claide"
10
+ require "pathname"
11
+ require "cork"
12
+
13
+ module Nabokov
14
+ end
data/nabokov.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "nabokov/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "nabokov"
8
+ spec.version = Nabokov::VERSION
9
+ spec.authors = ["Anton Domashnev"]
10
+ spec.email = ["antondomashnev@gmail.com"]
11
+ spec.description = Nabokov::DESCRIPTION
12
+ spec.summary = "Move mobile localization boringness away from you 🏃"
13
+ spec.homepage = "https://github.com/Antondomashnev/nabokov"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.required_ruby_version = ">= 2.0.0"
22
+
23
+ spec.add_runtime_dependency "rspec", "~> 3.4"
24
+ spec.add_runtime_dependency "git", "~> 1.0"
25
+ spec.add_runtime_dependency "claide", "~> 1.0"
26
+ spec.add_runtime_dependency "cork", "~> 0.1"
27
+
28
+ spec.add_development_dependency "rubocop", "~> 0.42"
29
+ spec.add_development_dependency "bundler", "~> 1.3"
30
+ spec.add_development_dependency "rake"
31
+ end
Binary file
@@ -0,0 +1 @@
1
+ Nabokov template repo for specs
@@ -0,0 +1 @@
1
+ "hello" = "hallo";
@@ -0,0 +1 @@
1
+ "hello" = "hello";
@@ -0,0 +1,9 @@
1
+ localizations_repo:
2
+ url: 'https://github.com/Antondomashnev/nabokov_example.git'
3
+ master_branch: 'shmaster'
4
+
5
+ project_repo:
6
+ localizations:
7
+ :en: 'spec/fixtures/en.strings'
8
+ :de: 'spec/fixtures/de.strings'
9
+ local_path: 'spec/fixtures/local_project'
@@ -0,0 +1,2 @@
1
+ localizations_repo: 'bla_bla_bla'
2
+ localizations fake
@@ -0,0 +1,8 @@
1
+ localizations_repo:
2
+ url: 'https://github.com/Antondomashnev/nabokov_example.git'
3
+
4
+ project_repo:
5
+ localizations:
6
+ :en: 'spec/fixtures/en.strings'
7
+ :de: 'spec/fixtures/de.strings'
8
+ local_path: 'spec/fixtures/local_project'
@@ -0,0 +1 @@
1
+ Nabokov template repo for specs
@@ -0,0 +1,8 @@
1
+ localizations_repo:
2
+ url: 'https://github.com/Antondomashnev/nabokov_example.git'
3
+
4
+ project_repo:
5
+ localizations:
6
+ :en: 'spec/fixtures/en.strings'
7
+ :de: 'spec/fixtures/de.strings'
8
+ local_path: 'spec/fixtures/local_project'
@@ -0,0 +1,2 @@
1
+ "hello" = "Hallo";
2
+ "bye" = "Tschuss";
@@ -0,0 +1,2 @@
1
+ "hello" = "Hello";
2
+ "bye" = "Bye";
@@ -0,0 +1,2 @@
1
+ "hello" = "Hello";
2
+ "bye" = "Bye";
@@ -0,0 +1,2 @@
1
+ "hello" = "Hello";
2
+ "bye" = "Bye";
@@ -0,0 +1,9 @@
1
+ localizations_repo:
2
+ url: 'https://github.com/Antondomashnev/nabokov_example.git'
3
+ master_branch: 'master'
4
+
5
+ project_repo:
6
+ localizations:
7
+ :en: 'spec/fixtures/test_project_syncer/project_repo/en.strings'
8
+ :de: 'spec/fixtures/test_project_syncer/project_repo/de.strings'
9
+ local_path: 'spec/fixtures/test_project_syncer/project_repo'