phraseapp_updater 0.1.4 → 0.1.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1b4b5ca69acb3ee2e8aa1b40c1325872ac307c50
4
- data.tar.gz: 0f1e8961e0e35908ab8c8094ee845a9d71c8badf
3
+ metadata.gz: a0c061126d02d4f01d387770c2c9340336be6e5f
4
+ data.tar.gz: 31e72d551e6852fa680e477c2e0a9ba185bd5160
5
5
  SHA512:
6
- metadata.gz: 70c04afe5d8a011e3f7d68872f82bfa7a67150c6868d29f2b7b2a0990647a9496a92165c1d44f7753ec72b59b4fd5649f0e93b41ca68c8041829f830033d3715
7
- data.tar.gz: b6880095d635a3b72dade7bbe19ea363b6c1fb38db91cae84f230e307f34f9f7757e6b9a3bfdcdeeb208a36f3d8689705f5bc58211916bf1f68df44db5c60720
6
+ metadata.gz: 6b64d248d78459245df8f5f17121b85268f11cf35273addb88d8d8f876e3d24325644d6ba7696f112bca6003aefc5c8e3ac752c3a4a64e6959246bfe89d93203
7
+ data.tar.gz: 4ada8a07261f8e5966a6a72ed5f8223bf18999704fccfaa1f1f7c6dc4d98506b8195ed8a179b1287aef6fe88e4031ba431bffbe71e76dd5d7cc5a651a2fae848
data/README.markdown CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/iknow/phraseapp_updater.svg?branch=master)](https://travis-ci.org/iknow/phraseapp_updater)
4
4
 
5
- **Version** 0.1.4
5
+ **Version** 0.1.5
6
6
 
7
7
  This is a tool for merging PhraseApp locale data with locale data
8
8
  committed in your project.
@@ -89,7 +89,7 @@ committed to your application's respository. These will be used in the
89
89
  merge with the files on PhraseApp.
90
90
 
91
91
  ```
92
- phraseapp_updater push --new_locales_path="/data/previous", --previous_locales_path="/data/new" --phraseapp_api_key="yourkey" --phraseapp_project_id="projectid"
92
+ phraseapp_updater push --new_locales_path="/data/previous", --previous_locales_path="/data/new" --phraseapp_api_key="yourkey" --phraseapp_project_id="projectid --file_format=json"
93
93
  ```
94
94
 
95
95
  The arguments provided to the command can also be specified as shell
@@ -100,6 +100,7 @@ PA_NEW_LOCALES_PATH
100
100
  PA_PREVIOUS_LOCALES_PATH
101
101
  PA_API_KEY
102
102
  PA_PROJECT_ID
103
+ PA_FILE_FORMAT
103
104
  ```
104
105
 
105
106
  Additionally, PhraseApp credentials can be loaded from a
@@ -118,7 +119,7 @@ If you want to pull without this fallback behavior, PhraseApp's [client](https:/
118
119
  is the best tool to use.
119
120
 
120
121
  ```
121
- phraseapp_updater pull --fallback_path="/data/app/locales" --phraseapp_api_key="yourkey" --phraseapp_project_id="projectid"
122
+ phraseapp_updater pull --fallback_path="/data/app/locales" --phraseapp_api_key="yourkey" --phraseapp_project_id="projectid --file_format=json""
122
123
  ```
123
124
 
124
125
  The PhraseApp data passed to the command can also be specified as shell
@@ -127,6 +128,7 @@ variables:
127
128
  ```
128
129
  PA_API_KEY
129
130
  PA_PROJECT_ID
131
+ PA_FILE_FORMAT
130
132
  ```
131
133
 
132
134
  Additionally, PhraseApp credentials can be loaded from a
@@ -138,8 +140,8 @@ Ruby
138
140
  `PhraseAppUpdater.push` and `PhraseAppUpdater.pull` are analogous to the command line versions:
139
141
 
140
142
  ```ruby
141
- PhraseAppUpdater.push("api_key", "project_id", "previous/path", "current/path")
142
- PhraseAppUpdater.pull("api_key", "project_id", "fallback/path")
143
+ PhraseAppUpdater.new("api_key", "project_id", "file_format").push("previous/path", "current/path")
144
+ PhraseAppUpdater.new("api_key", "project_id", "file_format").pull("fallback/path")
143
145
  ```
144
146
 
145
147
 
@@ -11,9 +11,10 @@ class PhraseAppUpdaterCLI < Thor
11
11
  option :config_file_path, type: :string, desc: "Path to .phraseapp.yml config file to read API key and project ID."
12
12
  option :store_results_path, type: :string, desc: "Path to write the resolved files. Shell variable: PA_STORE_RESULTS_PATH"
13
13
  option :store_phraseapp_originals_path, type: :string, desc: "Path to write the files downloaded from PhraseApp before the merge. Shell variable: PA_STORE_PHRASEAPP_ORIGINALS_PATH"
14
+ option :file_format, type: :string, desc: "Filetype of localization files."
14
15
 
15
16
  def push
16
- phraseapp_api_key, phraseapp_project_id = load_phraseapp_credentials(options)
17
+ phraseapp_api_key, phraseapp_project_id, file_format = load_phraseapp_configuration(options)
17
18
 
18
19
  new_locales_path = options.fetch(:new_locales_path, ENV["PA_NEW_LOCALES_PATH"]).to_s
19
20
  validate_readable_path!('new_locales_path', new_locales_path)
@@ -28,7 +29,7 @@ class PhraseAppUpdaterCLI < Thor
28
29
  validate_writable_path!('store_phraseapp_originals_path', store_phraseapp_originals_path)
29
30
 
30
31
  begin
31
- result = PhraseAppUpdater.new(phraseapp_api_key, phraseapp_project_id).push(previous_locales_path, new_locales_path)
32
+ result = PhraseAppUpdater.new(phraseapp_api_key, phraseapp_project_id, file_format).push(previous_locales_path, new_locales_path)
32
33
 
33
34
  unless store_results_path.empty?
34
35
  write_locale_files(store_results_path, result.resolved_files)
@@ -41,8 +42,10 @@ class PhraseAppUpdaterCLI < Thor
41
42
  puts "Bad PhraseApp API key."
42
43
  rescue PhraseAppUpdater::PhraseAppAPI::BadProjectIDError => e
43
44
  puts "Bad PhraseApp project ID: #{phraseapp_project_id}"
45
+ rescue PhraseAppUpdater::LocaleFile::BadFileTypeError => e
46
+ puts "Bad filetype for localization files: #{e.message}"
44
47
  rescue StandardError => e
45
- puts "Unknown error when pushing files"
48
+ puts "Unknown error when pushing files."
46
49
  raise e
47
50
  end
48
51
  end
@@ -56,7 +59,7 @@ class PhraseAppUpdaterCLI < Thor
56
59
  option :config_file_path, type: :string, desc: "Path to .phraseapp.yml config file to read API key and project ID."
57
60
 
58
61
  def pull
59
- phraseapp_api_key, phraseapp_project_id = load_phraseapp_credentials(options)
62
+ phraseapp_api_key, phraseapp_project_id, file_format = load_phraseapp_configuration(options)
60
63
 
61
64
  fallback_path = options[:fallback_path]
62
65
  validate_readable_path!('fallback_path', fallback_path)
@@ -65,12 +68,14 @@ class PhraseAppUpdaterCLI < Thor
65
68
  validate_writable_path!('destination_path', destination_path)
66
69
 
67
70
  begin
68
- files = PhraseAppUpdater.new(phraseapp_api_key, phraseapp_project_id).pull(fallback_path)
71
+ files = PhraseAppUpdater.new(phraseapp_api_key, phraseapp_project_id, file_format).pull(fallback_path)
69
72
  write_locale_files(destination_path, files)
70
73
  rescue PhraseAppUpdater::PhraseAppAPI::BadAPIKeyError => e
71
74
  puts "Bad PhraseApp API key."
72
75
  rescue PhraseAppUpdater::PhraseAppAPI::BadProjectIDError => e
73
76
  puts "Bad PhraseApp project ID: #{phraseapp_project_id}"
77
+ rescue PhraseAppUpdater::LocaleFile::BadFileTypeError => e
78
+ puts "Bad filetype for localization files: #{e.message}"
74
79
  rescue StandardError => e
75
80
  puts "Unknown error when pulling files"
76
81
  raise e
@@ -92,10 +97,10 @@ class PhraseAppUpdaterCLI < Thor
92
97
 
93
98
  private
94
99
 
95
- def load_phraseapp_credentials(options)
100
+ def load_phraseapp_configuration(options)
96
101
  if options[:config_file_path]
97
102
 
98
- if options[:phraseapp_api_key] || options[:phraseapp_project_id]
103
+ if [:phraseapp_api_key, :phraseapp_project_id, :file_format].any? { |option| options.has_key?(:option) }
99
104
  raise RuntimeError.new("Provided both a path to PhraseApp config file and command line arguments. Specify only one. #{options}")
100
105
  end
101
106
 
@@ -103,9 +108,11 @@ class PhraseAppUpdaterCLI < Thor
103
108
 
104
109
  phraseapp_api_key = config.api_key
105
110
  phraseapp_project_id = config.project_id
111
+ file_format = config.file_format
106
112
  else
107
113
  phraseapp_api_key = options.fetch(:phraseapp_api_key, ENV["PA_API_KEY"]).to_s
108
114
  phraseapp_project_id = options.fetch(:phraseapp_project_id, ENV["PA_PROJECT_ID"]).to_s
115
+ file_format = options.fetch(:file_format, ENV["PA_FILE_FORMAT"]).to_s
109
116
  end
110
117
 
111
118
  if phraseapp_api_key.empty?
@@ -116,7 +123,11 @@ class PhraseAppUpdaterCLI < Thor
116
123
  raise RuntimeError.new("Must provide Phraseapp project ID. --phraseapp_project_id or PA_PROJECT_ID")
117
124
  end
118
125
 
119
- return [phraseapp_api_key, phraseapp_project_id]
126
+ if file_format.empty?
127
+ raise RuntimeError.new("Must provide file format for Phraseapp project. --file_format or PA_FILE_FORMAT")
128
+ end
129
+
130
+ return [phraseapp_api_key, phraseapp_project_id, file_format]
120
131
  end
121
132
 
122
133
  def validate_path!(name, path)
@@ -2,15 +2,16 @@ require 'phraseapp_updater/version'
2
2
  require 'phraseapp_updater/index_by'
3
3
  require 'phraseapp_updater/differ'
4
4
  require 'phraseapp_updater/locale_file'
5
- require 'phraseapp_updater/locale_file_loader'
5
+ require 'phraseapp_updater/locale_file/loader'
6
6
  require 'phraseapp_updater/phraseapp_api'
7
7
  require 'phraseapp_updater/yml_config_loader'
8
8
 
9
9
  class PhraseAppUpdater
10
10
  using IndexBy
11
11
 
12
- def initialize(phraseapp_api_key, phraseapp_project_id)
13
- @phraseapp_api = PhraseAppAPI.new(phraseapp_api_key, phraseapp_project_id)
12
+ def initialize(phraseapp_api_key, phraseapp_project_id, file_format)
13
+ @locale_file_class = LocaleFile.class_for_file_format(file_format)
14
+ @phraseapp_api = PhraseAppAPI.new(phraseapp_api_key, phraseapp_project_id, @locale_file_class)
14
15
  end
15
16
 
16
17
  def self.load_config(config_file_path)
@@ -38,7 +39,7 @@ class PhraseAppUpdater
38
39
  primary: new_locale_file.parsed_content,
39
40
  secondary: phraseapp_file.parsed_content)
40
41
 
41
- LocaleFile.from_hash(previous_locale_file.name, resolved_content)
42
+ @locale_file_class.from_hash(previous_locale_file.name, resolved_content)
42
43
  end
43
44
 
44
45
  # Upload all of the secondary languages first,
@@ -88,7 +89,7 @@ class PhraseAppUpdater
88
89
  fallback = clear_empty_strings!(fallback_files[phraseapp_without_unverified_file.name].parsed_content)
89
90
 
90
91
  restore_unverified_originals!(fallback, with_unverified, without_unverified)
91
- LocaleFile.from_hash(phraseapp_without_unverified_file.name, without_unverified)
92
+ @locale_file_class.from_hash(phraseapp_without_unverified_file.name, without_unverified)
92
93
  end
93
94
  end
94
95
 
@@ -107,8 +108,9 @@ class PhraseAppUpdater
107
108
  end
108
109
 
109
110
  def load_locale_files(*paths)
111
+ loader = LocaleFile::Loader.new(@locale_file_class::EXTENSION)
110
112
  paths.map do |path|
111
- LocaleFileLoader.filenames(path).map { |l| LocaleFileLoader.load(l) }
113
+ loader.filenames(path).map { |l| loader.load(l) }
112
114
  end
113
115
  end
114
116
 
@@ -1,18 +1,28 @@
1
- require 'multi_json'
2
- require 'oj'
3
-
4
- # We're working with pure JSON, not
5
- # serialized Ruby objects
6
- Oj.default_options = {mode: :strict}
1
+ require "phraseapp_updater/locale_file/json_file"
2
+ require "phraseapp_updater/locale_file/yaml_file"
7
3
 
8
4
  class PhraseAppUpdater
9
5
  class LocaleFile
10
6
  attr_reader :name, :content, :parsed_content
11
7
 
8
+ class BadFileTypeError < StandardError ; end
9
+
12
10
  def self.from_hash(name, hash)
13
- new(name, MultiJson.dump(hash))
11
+ raise RuntimeError.new("Must be implemented in a subclass.")
12
+ end
13
+
14
+ def self.class_for_file_format(type)
15
+ case type.downcase
16
+ when "json"
17
+ JSONFile
18
+ when "yml", "yaml"
19
+ YAMLFile
20
+ else
21
+ raise BadFileTypeError.new("Invalid file type: #{type}")
22
+ end
14
23
  end
15
24
 
25
+ # Expects a Ruby hash
16
26
  def initialize(name, content)
17
27
  @name = name
18
28
  @content = content
@@ -25,20 +35,17 @@ class PhraseAppUpdater
25
35
  end
26
36
 
27
37
  def name_with_extension
28
- "#{name}.json"
38
+ "#{name}.#{self.class::EXTENSION}"
29
39
  end
30
40
 
31
41
  private
32
42
 
33
43
  def parse(content)
34
- MultiJson.load(content)
35
- rescue MultiJson::ParseError => e
36
- raise ArgumentError.new("Provided content was not valid JSON")
44
+ raise RuntimeError.new("Must be implemented in a subclass.")
37
45
  end
38
46
 
39
47
  def format_content!
40
- # Add indentation for better diffs
41
- @content = MultiJson.dump(MultiJson.load(@content), pretty: true)
48
+ raise RuntimeError.new("Must be implemented in a subclass.")
42
49
  end
43
50
  end
44
51
  end
@@ -0,0 +1,29 @@
1
+ require 'multi_json'
2
+ require 'oj'
3
+
4
+ # We're working with pure JSON, not
5
+ # serialized Ruby objects
6
+ Oj.default_options = {mode: :strict}
7
+
8
+ class PhraseAppUpdater
9
+ class LocaleFile
10
+ class JSONFile < LocaleFile
11
+ EXTENSION = "json"
12
+ def self.from_hash(name, hash)
13
+ new(name, MultiJson.dump(hash))
14
+ end
15
+
16
+ def parse(content)
17
+ MultiJson.load(content)
18
+ rescue MultiJson::ParseError => e
19
+ raise ArgumentError.new("Provided content was not valid JSON: #{e}")
20
+ end
21
+
22
+ def format_content!
23
+ # Add indentation for better diffs
24
+ @content = MultiJson.dump(MultiJson.load(@content), pretty: true)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
@@ -0,0 +1,24 @@
1
+ require 'phraseapp_updater/locale_file'
2
+
3
+ class PhraseAppUpdater
4
+ class LocaleFile
5
+ class Loader
6
+ def initialize(extension)
7
+ @extension = extension
8
+ end
9
+
10
+ def load(filename)
11
+ unless File.readable?(filename) && File.file?(filename)
12
+ raise RuntimeError.new("Couldn't read localization file at #{filename}")
13
+ end
14
+
15
+ LocaleFile.class_for_file_format(@extension).new(File.basename(filename).chomp(".#{@extension}"), File.read(filename))
16
+ end
17
+
18
+ def filenames(locale_directory)
19
+ Dir["#{locale_directory}/*.#{@extension}"]
20
+ end
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,20 @@
1
+ require 'psych'
2
+ class PhraseAppUpdater
3
+ class LocaleFile
4
+ class YAMLFile < LocaleFile
5
+ EXTENSION = "yml"
6
+ def self.from_hash(name, hash)
7
+ new(name, Psych.dump(hash))
8
+ end
9
+
10
+ def parse(content)
11
+ Psych.load(content)
12
+ rescue Psych::SyntaxError => e
13
+ raise ArgumentError.new("Provided content was not valid YAML")
14
+ end
15
+
16
+ def format_content!
17
+ end
18
+ end
19
+ end
20
+ end
@@ -4,9 +4,10 @@ require 'thread'
4
4
 
5
5
  class PhraseAppUpdater
6
6
  class PhraseAppAPI
7
- def initialize(api_key, project_id)
8
- @client = PhraseApp::Client.new(PhraseApp::Auth::Credentials.new(token: api_key))
9
- @project_id = project_id
7
+ def initialize(api_key, project_id, locale_file_class)
8
+ @client = PhraseApp::Client.new(PhraseApp::Auth::Credentials.new(token: api_key))
9
+ @project_id = project_id
10
+ @locale_file_class = locale_file_class
10
11
  end
11
12
 
12
13
  def download_locales
@@ -23,7 +24,7 @@ class PhraseAppUpdater
23
24
  puts "Downloading file for #{locale}"
24
25
  download_file(locale, skip_unverified)
25
26
  end.map do |locale, file_contents|
26
- LocaleFile.new(locale.name, file_contents)
27
+ @locale_file_class.new(locale.name, file_contents)
27
28
  end
28
29
  end
29
30
 
@@ -1,3 +1,3 @@
1
1
  class PhraseAppUpdater
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
  end
@@ -2,7 +2,7 @@ require 'yaml'
2
2
 
3
3
  class PhraseAppUpdater
4
4
  class YMLConfigLoader
5
- attr_reader :api_key, :project_id
5
+ attr_reader :api_key, :project_id, :file_format
6
6
  def initialize(file_path)
7
7
  unless File.readable?(file_path)
8
8
  raise RuntimeError.new("Can't read config file at #{file_path}")
@@ -14,8 +14,33 @@ class PhraseAppUpdater
14
14
  raise RuntimeError.new("Couldn't parse file contents: #{File.read(file_path)}")
15
15
  end
16
16
 
17
- @api_key = parsed_yaml.fetch("phraseapp").fetch("access_token")
18
- @project_id = parsed_yaml.fetch("phraseapp").fetch("project_id")
17
+ config = parsed_yaml.fetch("phraseapp")
18
+
19
+ @api_key = config.fetch("access_token")
20
+ @project_id = config.fetch("project_id")
21
+
22
+ push_file_format = config.fetch("push").fetch("sources").first.fetch("params").fetch("file_format")
23
+ pull_file_format = config.fetch("pull").fetch("targets").first.fetch("params").fetch("file_format")
24
+
25
+ unless push_file_format == pull_file_format
26
+ raise ArgumentError.new("Push and pull must be the same format")
27
+ end
28
+
29
+ @file_format = convert(push_file_format)
30
+ end
31
+
32
+
33
+ private
34
+
35
+ def convert(phraseapp_file_format)
36
+ case phraseapp_file_format
37
+ when "nested_json"
38
+ "json"
39
+ when "yml"
40
+ "yml"
41
+ else
42
+ raise ArugmentError.new("Unsupported type: #{phraseapp_file_format}")
43
+ end
19
44
  end
20
45
  end
21
46
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phraseapp_updater
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Griffin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-21 00:00:00.000000000 Z
11
+ date: 2017-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -174,7 +174,9 @@ files:
174
174
  - lib/phraseapp_updater/differ.rb
175
175
  - lib/phraseapp_updater/index_by.rb
176
176
  - lib/phraseapp_updater/locale_file.rb
177
- - lib/phraseapp_updater/locale_file_loader.rb
177
+ - lib/phraseapp_updater/locale_file/json_file.rb
178
+ - lib/phraseapp_updater/locale_file/loader.rb
179
+ - lib/phraseapp_updater/locale_file/yaml_file.rb
178
180
  - lib/phraseapp_updater/phraseapp_api.rb
179
181
  - lib/phraseapp_updater/version.rb
180
182
  - lib/phraseapp_updater/yml_config_loader.rb
@@ -199,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
199
201
  version: '0'
200
202
  requirements: []
201
203
  rubyforge_project:
202
- rubygems_version: 2.5.1
204
+ rubygems_version: 2.6.11
203
205
  signing_key:
204
206
  specification_version: 4
205
207
  summary: A three-way differ for PhraseApp projects.
@@ -1,18 +0,0 @@
1
- require 'phraseapp_updater/locale_file'
2
-
3
- class PhraseAppUpdater
4
- class LocaleFileLoader
5
- def self.load(filename)
6
- unless File.readable?(filename) && File.file?(filename)
7
- raise RuntimeError.new("Couldn't read localization file at #{filename}")
8
- end
9
-
10
- LocaleFile.new(File.basename(filename).chomp(".json"), File.read(filename))
11
- end
12
-
13
- def self.filenames(locale_directory)
14
- Dir["#{locale_directory}/*.json"]
15
- end
16
- end
17
- end
18
-