dotstrings 0.2.0 → 0.4.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 +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +3 -2
- data/lib/dotstrings/errors.rb +2 -0
- data/lib/dotstrings/file.rb +133 -0
- data/lib/dotstrings/item.rb +18 -0
- data/lib/dotstrings/parser.rb +44 -16
- data/lib/dotstrings/version.rb +1 -1
- data/lib/dotstrings.rb +14 -0
- metadata +19 -44
- data/.editorconfig +0 -13
- data/.github/workflows/ci.yml +0 -33
- data/.gitignore +0 -2
- data/.rubocop.yml +0 -41
- data/Gemfile +0 -5
- data/Gemfile.lock +0 -49
- data/Rakefile +0 -10
- data/dotstrings.gemspec +0 -28
- data/test/fixtures/escaped_backslashes.strings +0 -2
- data/test/fixtures/escaped_carriage_returns.strings +0 -2
- data/test/fixtures/escaped_new_lines.strings +0 -2
- data/test/fixtures/escaped_nil.strings +0 -2
- data/test/fixtures/escaped_quotes.strings +0 -2
- data/test/fixtures/escaped_single_quotes.strings +0 -2
- data/test/fixtures/escaped_tabs.strings +0 -2
- data/test/fixtures/escaped_unicode.strings +0 -2
- data/test/fixtures/utf16be_bom.strings +0 -0
- data/test/fixtures/utf16le_bom.strings +0 -0
- data/test/fixtures/utf8_bom.strings +0 -2
- data/test/fixtures/valid.strings +0 -8
- data/test/helper.rb +0 -8
- data/test/test_dotstrings.rb +0 -107
- data/test/test_file.rb +0 -94
- data/test/test_item.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9c320ba9bef4d63af10c9c9fd3d91ad41da99b3663538f0b89ebdc6fc780d31
|
4
|
+
data.tar.gz: 24e762927cd739f3475a8a550a751f808dd81d73292e47f7449c657edeaa88db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f24ad0efde29b52a33f28cd0e434970bde12556d9236c632495eebdfd089ed550e54a41f67fb844c70677c53bbdaccdbb93f593cafd535062532f062297ab7b4
|
7
|
+
data.tar.gz: d61a17f762188162a431c6289b96e23d4374ca2a29a82e84b58e92bf097d79746a352418859e12c2d1dcf13c8844a53a9975360be6c0a98f65d046c16aba45cc
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v0.4.0] - 2022-09-18
|
4
|
+
### Added
|
5
|
+
* Added `DotStrings::File#each`, `DotStrings::File#length`, `DotStrings::File#count`, and `DotStrings::File#empty?` methods.
|
6
|
+
* Allow comparing `DotStrings::File` objects.
|
7
|
+
|
8
|
+
## [v0.3.0] - 2022-08-07
|
9
|
+
### Changed
|
10
|
+
* Improved unicode code point parsing and validation.
|
11
|
+
* Added `DotStrings::File#sort`, `DotStrings::File#sort!`, and `DotStrings::File#delete_if` methods.
|
12
|
+
* Improved documentation.
|
13
|
+
|
3
14
|
## [v0.2.0] - 2022-07-17
|
4
15
|
### Changed
|
5
16
|
* Made some state transitions more strict.
|
@@ -13,6 +24,8 @@
|
|
13
24
|
### Added
|
14
25
|
* Initial release.
|
15
26
|
|
27
|
+
[v0.4.0]: https://github.com/raymondjavaxx/dotstrings/releases/tag/v0.4.0
|
28
|
+
[v0.3.0]: https://github.com/raymondjavaxx/dotstrings/releases/tag/v0.3.0
|
16
29
|
[v0.2.0]: https://github.com/raymondjavaxx/dotstrings/releases/tag/v0.2.0
|
17
30
|
[v0.1.1]: https://github.com/raymondjavaxx/dotstrings/releases/tag/v0.1.1
|
18
31
|
[v0.1.0]: https://github.com/raymondjavaxx/dotstrings/releases/tag/v0.1.0
|
data/README.md
CHANGED
@@ -7,6 +7,7 @@ A parser for Apple *strings* files (`.strings`) written in Ruby. Some of the fea
|
|
7
7
|
* An API for creating strings files programmatically.
|
8
8
|
* Handles Unicode and escaped characters.
|
9
9
|
* Helpful error messages: know which line and column fail to parse and why.
|
10
|
+
* Well [tested](test) and [documented](https://www.rubydoc.info/gems/dotstrings/DotStrings).
|
10
11
|
|
11
12
|
## Installing
|
12
13
|
|
@@ -19,12 +20,12 @@ $ gem install dotstrings
|
|
19
20
|
Or by adding the following entry to your [Gemfile](https://guides.cocoapods.org/using/a-gemfile.html), then running `$ bundle install`.
|
20
21
|
|
21
22
|
```ruby
|
22
|
-
gem
|
23
|
+
gem 'dotstrings'
|
23
24
|
```
|
24
25
|
|
25
26
|
## Usage
|
26
27
|
|
27
|
-
You can load `.strings` files using the `DotString.parse()` utility method. This method returns a `DotStrings::File` object or raises an exception if the file
|
28
|
+
You can load `.strings` files using the `DotString.parse()` utility method. This method returns a `DotStrings::File` object or raises an exception if the file cannot be parsed.
|
28
29
|
|
29
30
|
```ruby
|
30
31
|
file = DotStrings.parse_file('en-US/Localizable.strings')
|
data/lib/dotstrings/errors.rb
CHANGED
data/lib/dotstrings/file.rb
CHANGED
@@ -5,13 +5,48 @@ require 'dotstrings/errors'
|
|
5
5
|
require 'dotstrings/item'
|
6
6
|
|
7
7
|
module DotStrings
|
8
|
+
##
|
9
|
+
# Represents a .strings file.
|
10
|
+
#
|
11
|
+
# It provides methods to parse .strings, as well as methods for accessing and
|
12
|
+
# manipulating localized string items.
|
8
13
|
class File
|
14
|
+
##
|
15
|
+
# All items in the file.
|
9
16
|
attr_reader :items
|
10
17
|
|
11
18
|
def initialize(items = [])
|
12
19
|
@items = items
|
13
20
|
end
|
14
21
|
|
22
|
+
##
|
23
|
+
# Returns a new File with the items sorted using the given comparator block.
|
24
|
+
#
|
25
|
+
# If no block is given, the items will be sorted by key.
|
26
|
+
def sort(&block)
|
27
|
+
new_file = dup
|
28
|
+
new_file.sort!(&block)
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Sort the items using the given block.
|
33
|
+
#
|
34
|
+
# If no block is given, the items will be sorted by key.
|
35
|
+
def sort!(&block)
|
36
|
+
@items.sort!(&block || ->(a, b) { a.key <=> b.key })
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Parses a file from the given IO object.
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# io = Zlib::GzipReader.open('path/to/en.lproj/Localizable.strings.gz')
|
45
|
+
# file = DotStrings::File.parse(io)
|
46
|
+
#
|
47
|
+
# @param io [IO] The IO object to parse.
|
48
|
+
# @return [DotStrings::File] The parsed file.
|
49
|
+
# @raise [DotStrings::ParsingError] if the file could not be parsed.
|
15
50
|
def self.parse(io)
|
16
51
|
items = []
|
17
52
|
|
@@ -22,32 +57,130 @@ module DotStrings
|
|
22
57
|
File.new(items)
|
23
58
|
end
|
24
59
|
|
60
|
+
##
|
61
|
+
# Parses the file at the given path.
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# file = DotStrings::File.parse_file('path/to/en.lproj/Localizable.strings')
|
65
|
+
#
|
66
|
+
# @param path [String] The path to the file to parse.
|
67
|
+
# @return [DotStrings::File] The parsed file.
|
68
|
+
# @raise [DotStrings::ParsingError] if the file could not be parsed.
|
25
69
|
def self.parse_file(path)
|
26
70
|
::File.open(path, 'r') do |file|
|
27
71
|
parse(file)
|
28
72
|
end
|
29
73
|
end
|
30
74
|
|
75
|
+
##
|
76
|
+
# Returns all keys in the file.
|
31
77
|
def keys
|
32
78
|
@items.map(&:key)
|
33
79
|
end
|
34
80
|
|
81
|
+
##
|
82
|
+
# Returns an item by key, if it exists, otherwise nil.
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
# item = file['button.title']
|
86
|
+
# unless item.nil?
|
87
|
+
# puts item.value # => 'Submit'
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# @param key [String] The key of the item to return.
|
91
|
+
# @return [DotStrings::Item] The item, if it exists.
|
35
92
|
def [](key)
|
36
93
|
@items.find { |item| item.key == key }
|
37
94
|
end
|
38
95
|
|
96
|
+
##
|
97
|
+
# Appends an item to the file.
|
98
|
+
#
|
99
|
+
# @example
|
100
|
+
# file << DotStrings::Item.new(key: 'button.title', value: 'Submit')
|
101
|
+
#
|
102
|
+
# @param item [DotStrings::Item] The item to append.
|
103
|
+
# @return [DotStrings::Item] The item that was appended.
|
39
104
|
def <<(item)
|
40
105
|
@items << item
|
106
|
+
self
|
41
107
|
end
|
42
108
|
|
109
|
+
##
|
110
|
+
# Appends an item to the file.
|
111
|
+
#
|
112
|
+
# @example
|
113
|
+
# file.append(DotStrings::Item.new(key: 'button.title', value: 'Submit'))
|
43
114
|
def append(item)
|
44
115
|
self << item
|
45
116
|
end
|
46
117
|
|
118
|
+
##
|
119
|
+
# Deletes an item by key.
|
47
120
|
def delete(key)
|
48
121
|
@items.delete_if { |item| item.key == key }
|
49
122
|
end
|
50
123
|
|
124
|
+
##
|
125
|
+
# Deletes all items for which the block returns true.
|
126
|
+
#
|
127
|
+
# @example
|
128
|
+
# file.delete_if { |item| item.key.start_with?('button.') }
|
129
|
+
def delete_if(&block)
|
130
|
+
@items.delete_if(&block)
|
131
|
+
self
|
132
|
+
end
|
133
|
+
|
134
|
+
##
|
135
|
+
# Calls the given block once for each item in the file.
|
136
|
+
#
|
137
|
+
# @param block [Proc] The block to call.
|
138
|
+
# @example
|
139
|
+
# file.each do |item|
|
140
|
+
# puts "#{item.key} > #{item.value}"
|
141
|
+
# end
|
142
|
+
def each(&block)
|
143
|
+
@items.each(&block)
|
144
|
+
self
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Returns the number of items in the file.
|
149
|
+
def length
|
150
|
+
@items.length
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# Returns the number of items in the file.
|
155
|
+
#
|
156
|
+
# If a block is given, it will count the number of items for which the block returns true.
|
157
|
+
#
|
158
|
+
# @example
|
159
|
+
# file.count # => 10
|
160
|
+
# file.count { |item| item.key.start_with?('button.') } # => 3
|
161
|
+
def count(&block)
|
162
|
+
@items.count(&block)
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Returns `true` if the file doen't contain any items.
|
167
|
+
def empty?
|
168
|
+
@items.empty?
|
169
|
+
end
|
170
|
+
|
171
|
+
def ==(other)
|
172
|
+
eql?(other)
|
173
|
+
end
|
174
|
+
|
175
|
+
def eql?(other)
|
176
|
+
other.is_a?(self.class) && @items.eql?(other.items)
|
177
|
+
end
|
178
|
+
|
179
|
+
##
|
180
|
+
# Serializes the file to a string.
|
181
|
+
#
|
182
|
+
# @param escape_single_quotes [Boolean] whether to escape single quotes.
|
183
|
+
# @param comments [Boolean] whether to include comments.
|
51
184
|
def to_s(escape_single_quotes: false, comments: true)
|
52
185
|
result = []
|
53
186
|
|
data/lib/dotstrings/item.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DotStrings
|
4
|
+
##
|
5
|
+
# Represents a localized string item.
|
4
6
|
class Item
|
5
7
|
attr_reader :comment, :key, :value
|
6
8
|
|
@@ -10,6 +12,22 @@ module DotStrings
|
|
10
12
|
@value = value
|
11
13
|
end
|
12
14
|
|
15
|
+
def ==(other)
|
16
|
+
eql?(other)
|
17
|
+
end
|
18
|
+
|
19
|
+
def eql?(other)
|
20
|
+
other.is_a?(Item) &&
|
21
|
+
comment == other.comment &&
|
22
|
+
key == other.key &&
|
23
|
+
value == other.value
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Serializes the item to string.
|
28
|
+
#
|
29
|
+
# @param escape_single_quotes [Boolean] Whether to escape single quotes.
|
30
|
+
# @param include_comment [Boolean] Whether to include the comment.
|
13
31
|
def to_s(escape_single_quotes: false, include_comment: true)
|
14
32
|
result = []
|
15
33
|
|
data/lib/dotstrings/parser.rb
CHANGED
@@ -4,6 +4,9 @@ require 'dotstrings/errors'
|
|
4
4
|
|
5
5
|
module DotStrings
|
6
6
|
# rubocop:disable Metrics/ClassLength
|
7
|
+
|
8
|
+
##
|
9
|
+
# Parser for .strings files.
|
7
10
|
class Parser
|
8
11
|
# Special tokens
|
9
12
|
TOK_SLASH = '/'
|
@@ -36,8 +39,6 @@ module DotStrings
|
|
36
39
|
STATE_UNICODE_SURROGATE = 11
|
37
40
|
STATE_UNICODE_SURROGATE_U = 12
|
38
41
|
|
39
|
-
attr_reader :items
|
40
|
-
|
41
42
|
def initialize
|
42
43
|
@state = STATE_START
|
43
44
|
@temp_state = nil
|
@@ -59,11 +60,16 @@ module DotStrings
|
|
59
60
|
@column = 1
|
60
61
|
end
|
61
62
|
|
63
|
+
##
|
64
|
+
# Specifies a block to be called when a new item is parsed.
|
62
65
|
def on_item(&block)
|
63
66
|
@item_block = block
|
64
67
|
end
|
65
68
|
|
66
69
|
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/BlockLength
|
70
|
+
|
71
|
+
##
|
72
|
+
# Feeds data to the parser.
|
67
73
|
def <<(data)
|
68
74
|
data.each_char do |ch|
|
69
75
|
case @state
|
@@ -157,6 +163,7 @@ module DotStrings
|
|
157
163
|
update_position(ch)
|
158
164
|
end
|
159
165
|
end
|
166
|
+
|
160
167
|
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/BlockLength
|
161
168
|
|
162
169
|
private
|
@@ -203,30 +210,51 @@ module DotStrings
|
|
203
210
|
end
|
204
211
|
end
|
205
212
|
|
206
|
-
# rubocop:disable
|
213
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
207
214
|
def parse_unicode(ch, &block)
|
208
215
|
raise_error("Unexpected character '#{ch}', expecting a hex digit") unless ch =~ TOK_HEX_DIGIT
|
209
216
|
|
210
217
|
@unicode_buffer << ch
|
211
218
|
|
212
|
-
if
|
213
|
-
|
219
|
+
# Check if we have enough digits to form a codepoint.
|
220
|
+
return if @unicode_buffer.length < 4
|
214
221
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
block.call(codepoint.chr('UTF-8'))
|
222
|
+
codepoint = @unicode_buffer.join.hex
|
223
|
+
|
224
|
+
if codepoint >= 0xD800 && codepoint <= 0xDBFF
|
225
|
+
unless @high_surrogate.nil?
|
226
|
+
raise_error(
|
227
|
+
'Found a high surrogate code point after another high surrogate'
|
228
|
+
)
|
223
229
|
end
|
224
230
|
|
225
|
-
|
226
|
-
@
|
231
|
+
@high_surrogate = codepoint
|
232
|
+
@state = STATE_UNICODE_SURROGATE
|
233
|
+
elsif codepoint >= 0xDC00 && codepoint <= 0xDFFF
|
234
|
+
if @high_surrogate.nil?
|
235
|
+
raise_error(
|
236
|
+
'Found a low surrogate code point before a high surrogate'
|
237
|
+
)
|
238
|
+
end
|
239
|
+
|
240
|
+
character = ((@high_surrogate - 0xD800) * 0x400) + (codepoint - 0xDC00) + 0x10000
|
241
|
+
@high_surrogate = nil
|
242
|
+
|
243
|
+
block.call(character.chr('UTF-8'))
|
244
|
+
else
|
245
|
+
unless @high_surrogate.nil?
|
246
|
+
raise_error(
|
247
|
+
"Invalid unicode codepoint '\\U#{codepoint.to_s(16).upcase}' after a high surrogate code point"
|
248
|
+
)
|
249
|
+
end
|
250
|
+
|
251
|
+
block.call(codepoint.chr('UTF-8'))
|
227
252
|
end
|
253
|
+
|
254
|
+
# Clear buffer after codepoint is parsed
|
255
|
+
@unicode_buffer.clear
|
228
256
|
end
|
229
|
-
# rubocop:enable
|
257
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
230
258
|
|
231
259
|
def update_position(ch)
|
232
260
|
@offset += 1
|
data/lib/dotstrings/version.rb
CHANGED
data/lib/dotstrings.rb
CHANGED
@@ -6,10 +6,24 @@ require 'dotstrings/item'
|
|
6
6
|
require 'dotstrings/errors'
|
7
7
|
|
8
8
|
module DotStrings
|
9
|
+
##
|
10
|
+
# Parses a file from the given IO object.
|
11
|
+
#
|
12
|
+
# This is a convenience method for {DotStrings::File.parse}.
|
13
|
+
#
|
14
|
+
# @param io [IO] The IO object to parse.
|
15
|
+
# @return [DotStrings::File] The parsed file.
|
9
16
|
def self.parse(io)
|
10
17
|
File.parse(io)
|
11
18
|
end
|
12
19
|
|
20
|
+
##
|
21
|
+
# Parses a .strings file at the given path.
|
22
|
+
#
|
23
|
+
# This is a convenience method for {DotStrings::File.parse_file}.
|
24
|
+
#
|
25
|
+
# @param path [String] The path to the .strings file to parse.
|
26
|
+
# @return [DotStrings::File] The parsed file.
|
13
27
|
def self.parse_file(path)
|
14
28
|
File.parse_file(path)
|
15
29
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dotstrings
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ramon Torres
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simplecov
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
97
111
|
description: Parse and create .strings files used in localization of iOS and macOS
|
98
112
|
apps.
|
99
113
|
email:
|
@@ -102,39 +116,15 @@ executables: []
|
|
102
116
|
extensions: []
|
103
117
|
extra_rdoc_files: []
|
104
118
|
files:
|
105
|
-
- ".editorconfig"
|
106
|
-
- ".github/workflows/ci.yml"
|
107
|
-
- ".gitignore"
|
108
|
-
- ".rubocop.yml"
|
109
119
|
- CHANGELOG.md
|
110
|
-
- Gemfile
|
111
|
-
- Gemfile.lock
|
112
120
|
- LICENSE
|
113
121
|
- README.md
|
114
|
-
- Rakefile
|
115
|
-
- dotstrings.gemspec
|
116
122
|
- lib/dotstrings.rb
|
117
123
|
- lib/dotstrings/errors.rb
|
118
124
|
- lib/dotstrings/file.rb
|
119
125
|
- lib/dotstrings/item.rb
|
120
126
|
- lib/dotstrings/parser.rb
|
121
127
|
- lib/dotstrings/version.rb
|
122
|
-
- test/fixtures/escaped_backslashes.strings
|
123
|
-
- test/fixtures/escaped_carriage_returns.strings
|
124
|
-
- test/fixtures/escaped_new_lines.strings
|
125
|
-
- test/fixtures/escaped_nil.strings
|
126
|
-
- test/fixtures/escaped_quotes.strings
|
127
|
-
- test/fixtures/escaped_single_quotes.strings
|
128
|
-
- test/fixtures/escaped_tabs.strings
|
129
|
-
- test/fixtures/escaped_unicode.strings
|
130
|
-
- test/fixtures/utf16be_bom.strings
|
131
|
-
- test/fixtures/utf16le_bom.strings
|
132
|
-
- test/fixtures/utf8_bom.strings
|
133
|
-
- test/fixtures/valid.strings
|
134
|
-
- test/helper.rb
|
135
|
-
- test/test_dotstrings.rb
|
136
|
-
- test/test_file.rb
|
137
|
-
- test/test_item.rb
|
138
128
|
homepage: https://github.com/raymondjavaxx/dotstrings
|
139
129
|
licenses:
|
140
130
|
- MIT
|
@@ -155,24 +145,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
145
|
- !ruby/object:Gem::Version
|
156
146
|
version: '0'
|
157
147
|
requirements: []
|
158
|
-
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 2.7.6
|
159
150
|
signing_key:
|
160
151
|
specification_version: 4
|
161
152
|
summary: Parse and create .strings files used in localization of iOS and macOS apps.
|
162
|
-
test_files:
|
163
|
-
- test/fixtures/escaped_backslashes.strings
|
164
|
-
- test/fixtures/escaped_carriage_returns.strings
|
165
|
-
- test/fixtures/escaped_new_lines.strings
|
166
|
-
- test/fixtures/escaped_nil.strings
|
167
|
-
- test/fixtures/escaped_quotes.strings
|
168
|
-
- test/fixtures/escaped_single_quotes.strings
|
169
|
-
- test/fixtures/escaped_tabs.strings
|
170
|
-
- test/fixtures/escaped_unicode.strings
|
171
|
-
- test/fixtures/utf16be_bom.strings
|
172
|
-
- test/fixtures/utf16le_bom.strings
|
173
|
-
- test/fixtures/utf8_bom.strings
|
174
|
-
- test/fixtures/valid.strings
|
175
|
-
- test/helper.rb
|
176
|
-
- test/test_dotstrings.rb
|
177
|
-
- test/test_file.rb
|
178
|
-
- test/test_item.rb
|
153
|
+
test_files: []
|
data/.editorconfig
DELETED
data/.github/workflows/ci.yml
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
name: CI
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
branches: "*"
|
6
|
-
pull_request:
|
7
|
-
branches: "*"
|
8
|
-
|
9
|
-
jobs:
|
10
|
-
test:
|
11
|
-
runs-on: ubuntu-latest
|
12
|
-
strategy:
|
13
|
-
matrix:
|
14
|
-
ruby-version:
|
15
|
-
- "2.5"
|
16
|
-
- "2.6"
|
17
|
-
- "2.7"
|
18
|
-
- "3.0"
|
19
|
-
- "3.1"
|
20
|
-
|
21
|
-
steps:
|
22
|
-
- uses: actions/checkout@v2
|
23
|
-
- name: Set up Ruby
|
24
|
-
uses: ruby/setup-ruby@v1
|
25
|
-
with:
|
26
|
-
ruby-version: ${{ matrix.ruby-version }}
|
27
|
-
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
28
|
-
- name: Lint
|
29
|
-
run: bundle exec rake rubocop
|
30
|
-
- name: Run tests
|
31
|
-
run: bundle exec rake
|
32
|
-
- name: Install
|
33
|
-
run: bundle exec rake install
|
data/.gitignore
DELETED
data/.rubocop.yml
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
require:
|
2
|
-
- rubocop-rake
|
3
|
-
- rubocop-minitest
|
4
|
-
|
5
|
-
AllCops:
|
6
|
-
TargetRubyVersion: 2.5
|
7
|
-
NewCops: enable
|
8
|
-
|
9
|
-
Style/StringLiterals:
|
10
|
-
Enabled: true
|
11
|
-
EnforcedStyle: single_quotes
|
12
|
-
|
13
|
-
Layout/FirstHashElementIndentation:
|
14
|
-
Enabled: true
|
15
|
-
EnforcedStyle: consistent
|
16
|
-
|
17
|
-
Layout/FirstArrayElementIndentation:
|
18
|
-
Enabled: true
|
19
|
-
EnforcedStyle: consistent
|
20
|
-
|
21
|
-
Metrics/ClassLength:
|
22
|
-
Enabled: true
|
23
|
-
Max: 150
|
24
|
-
|
25
|
-
Naming/MethodParameterName:
|
26
|
-
Enabled: false
|
27
|
-
|
28
|
-
Metrics/MethodLength:
|
29
|
-
Enabled: false
|
30
|
-
|
31
|
-
Metrics/AbcSize:
|
32
|
-
Enabled: false
|
33
|
-
|
34
|
-
Style/Documentation:
|
35
|
-
Enabled: false
|
36
|
-
|
37
|
-
Style/ParallelAssignment:
|
38
|
-
Enabled: false
|
39
|
-
|
40
|
-
Minitest/AssertInDelta:
|
41
|
-
Enabled: false
|
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
dotstrings (0.2.0)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
ast (2.4.2)
|
10
|
-
minitest (5.15.0)
|
11
|
-
parallel (1.22.1)
|
12
|
-
parser (3.1.2.0)
|
13
|
-
ast (~> 2.4.1)
|
14
|
-
rainbow (3.1.1)
|
15
|
-
rake (13.0.6)
|
16
|
-
regexp_parser (2.5.0)
|
17
|
-
rexml (3.2.5)
|
18
|
-
rubocop (1.28.2)
|
19
|
-
parallel (~> 1.10)
|
20
|
-
parser (>= 3.1.0.0)
|
21
|
-
rainbow (>= 2.2.2, < 4.0)
|
22
|
-
regexp_parser (>= 1.8, < 3.0)
|
23
|
-
rexml
|
24
|
-
rubocop-ast (>= 1.17.0, < 2.0)
|
25
|
-
ruby-progressbar (~> 1.7)
|
26
|
-
unicode-display_width (>= 1.4.0, < 3.0)
|
27
|
-
rubocop-ast (1.17.0)
|
28
|
-
parser (>= 3.1.1.0)
|
29
|
-
rubocop-minitest (0.19.1)
|
30
|
-
rubocop (>= 0.90, < 2.0)
|
31
|
-
rubocop-rake (0.6.0)
|
32
|
-
rubocop (~> 1.0)
|
33
|
-
ruby-progressbar (1.11.0)
|
34
|
-
unicode-display_width (2.2.0)
|
35
|
-
|
36
|
-
PLATFORMS
|
37
|
-
ruby
|
38
|
-
|
39
|
-
DEPENDENCIES
|
40
|
-
bundler
|
41
|
-
dotstrings!
|
42
|
-
minitest (~> 5.14)
|
43
|
-
rake
|
44
|
-
rubocop
|
45
|
-
rubocop-minitest
|
46
|
-
rubocop-rake
|
47
|
-
|
48
|
-
BUNDLED WITH
|
49
|
-
2.2.18
|
data/Rakefile
DELETED
data/dotstrings.gemspec
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require './lib/dotstrings/version'
|
4
|
-
|
5
|
-
Gem::Specification.new do |s|
|
6
|
-
s.name = 'dotstrings'
|
7
|
-
s.version = DotStrings::VERSION
|
8
|
-
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = ['Ramon Torres']
|
10
|
-
s.email = ['raymondjavaxx@gmail.com']
|
11
|
-
s.homepage = 'https://github.com/raymondjavaxx/dotstrings'
|
12
|
-
s.description = s.summary = 'Parse and create .strings files used in localization of iOS and macOS apps.'
|
13
|
-
s.files = `git ls-files`.split("\n")
|
14
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
16
|
-
s.require_paths = ['lib']
|
17
|
-
s.license = 'MIT'
|
18
|
-
|
19
|
-
s.add_development_dependency 'bundler'
|
20
|
-
s.add_development_dependency 'minitest', '~> 5.14'
|
21
|
-
s.add_development_dependency 'rake'
|
22
|
-
s.add_development_dependency 'rubocop'
|
23
|
-
s.add_development_dependency 'rubocop-minitest'
|
24
|
-
s.add_development_dependency 'rubocop-rake'
|
25
|
-
|
26
|
-
s.required_ruby_version = '>= 2.5.0'
|
27
|
-
s.metadata['rubygems_mfa_required'] = 'true'
|
28
|
-
end
|
Binary file
|
Binary file
|
data/test/fixtures/valid.strings
DELETED
data/test/helper.rb
DELETED
data/test/test_dotstrings.rb
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'helper'
|
4
|
-
|
5
|
-
class TestDotStrings < MiniTest::Test
|
6
|
-
def test_parse_can_parse_valid_files
|
7
|
-
file = DotStrings.parse_file('test/fixtures/valid.strings')
|
8
|
-
|
9
|
-
assert_equal 3, file.items.size
|
10
|
-
|
11
|
-
assert_equal 'Single line comment', file.items[0].comment
|
12
|
-
assert_equal 'key 1', file.items[0].key
|
13
|
-
assert_equal 'value 1', file.items[0].value
|
14
|
-
|
15
|
-
assert_equal "Multi line\ncomment", file.items[1].comment
|
16
|
-
assert_equal 'key 2', file.items[1].key
|
17
|
-
assert_equal 'value 2', file.items[1].value
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_can_parse_file_with_escaped_quotes
|
21
|
-
file = DotStrings.parse_file('test/fixtures/escaped_quotes.strings')
|
22
|
-
|
23
|
-
assert_equal 1, file.items.size
|
24
|
-
assert_equal 'some "key"', file.items[0].key
|
25
|
-
assert_equal 'some "value"', file.items[0].value
|
26
|
-
end
|
27
|
-
|
28
|
-
def test_can_parse_file_with_escaped_single_quotes
|
29
|
-
file = DotStrings.parse_file('test/fixtures/escaped_single_quotes.strings')
|
30
|
-
|
31
|
-
assert_equal 1, file.items.size
|
32
|
-
assert_equal 'some \'key\'', file.items[0].key
|
33
|
-
assert_equal 'some \'value\'', file.items[0].value
|
34
|
-
end
|
35
|
-
|
36
|
-
def test_can_parse_file_with_escaped_tabs
|
37
|
-
file = DotStrings.parse_file('test/fixtures/escaped_tabs.strings')
|
38
|
-
|
39
|
-
assert_equal 1, file.items.size
|
40
|
-
assert_equal "some\tkey", file.items[0].key
|
41
|
-
assert_equal "some\tvalue", file.items[0].value
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_can_parse_files_with_escaped_carriage_returns
|
45
|
-
file = DotStrings.parse_file('test/fixtures/escaped_carriage_returns.strings')
|
46
|
-
|
47
|
-
assert_equal 1, file.items.size
|
48
|
-
assert_equal "some\rkey", file.items[0].key
|
49
|
-
assert_equal "some\rvalue", file.items[0].value
|
50
|
-
end
|
51
|
-
|
52
|
-
def test_can_parse_files_with_escaped_nil
|
53
|
-
file = DotStrings.parse_file('test/fixtures/escaped_nil.strings')
|
54
|
-
|
55
|
-
assert_equal 1, file.items.size
|
56
|
-
assert_equal "key\0", file.items[0].key
|
57
|
-
assert_equal "value\0", file.items[0].value
|
58
|
-
end
|
59
|
-
|
60
|
-
def test_can_parse_files_with_escaped_new_lines
|
61
|
-
file = DotStrings.parse_file('test/fixtures/escaped_new_lines.strings')
|
62
|
-
|
63
|
-
assert_equal 1, file.items.size
|
64
|
-
assert_equal "some\nkey", file.items[0].key
|
65
|
-
assert_equal "some\nvalue", file.items[0].value
|
66
|
-
end
|
67
|
-
|
68
|
-
def test_can_parse_files_with_escaped_backslashes
|
69
|
-
file = DotStrings.parse_file('test/fixtures/escaped_backslashes.strings')
|
70
|
-
|
71
|
-
assert_equal 1, file.items.size
|
72
|
-
assert_equal 'some\\key', file.items[0].key
|
73
|
-
assert_equal 'some\\value', file.items[0].value
|
74
|
-
end
|
75
|
-
|
76
|
-
def test_can_parse_files_with_escaped_unicode
|
77
|
-
file = DotStrings.parse_file('test/fixtures/escaped_unicode.strings')
|
78
|
-
|
79
|
-
assert_equal 1, file.items.size
|
80
|
-
assert_equal '$', file.items[0].key
|
81
|
-
assert_equal '⚡👻', file.items[0].value
|
82
|
-
end
|
83
|
-
|
84
|
-
def test_can_parse_utf16le_files_with_bom
|
85
|
-
file = DotStrings.parse_file('test/fixtures/utf16le_bom.strings')
|
86
|
-
|
87
|
-
assert_equal 1, file.items.size
|
88
|
-
assert_equal 'key', file.items[0].key
|
89
|
-
assert_equal 'value', file.items[0].value
|
90
|
-
end
|
91
|
-
|
92
|
-
def test_can_parse_utf16be_files_with_bom
|
93
|
-
file = DotStrings.parse_file('test/fixtures/utf16be_bom.strings')
|
94
|
-
|
95
|
-
assert_equal 1, file.items.size
|
96
|
-
assert_equal 'key', file.items[0].key
|
97
|
-
assert_equal 'value', file.items[0].value
|
98
|
-
end
|
99
|
-
|
100
|
-
def test_can_parse_utf8_files_with_bom
|
101
|
-
file = DotStrings.parse_file('test/fixtures/utf8_bom.strings')
|
102
|
-
|
103
|
-
assert_equal 1, file.items.size
|
104
|
-
assert_equal 'key', file.items[0].key
|
105
|
-
assert_equal 'value', file.items[0].value
|
106
|
-
end
|
107
|
-
end
|
data/test/test_file.rb
DELETED
@@ -1,94 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'helper'
|
4
|
-
|
5
|
-
class TestFile < MiniTest::Test
|
6
|
-
def test_delete
|
7
|
-
items = [
|
8
|
-
DotStrings::Item.new(key: 'key 1', value: 'value 1'),
|
9
|
-
DotStrings::Item.new(key: 'key 2', value: 'value 2'),
|
10
|
-
DotStrings::Item.new(key: 'key 3', value: 'value 3')
|
11
|
-
]
|
12
|
-
|
13
|
-
file = DotStrings::File.new(items)
|
14
|
-
|
15
|
-
file.delete('key 2')
|
16
|
-
assert_equal 2, file.items.size
|
17
|
-
assert_equal ['key 1', 'key 3'], file.keys
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_access_by_key
|
21
|
-
items = [
|
22
|
-
DotStrings::Item.new(key: 'key 1', value: 'value 1'),
|
23
|
-
DotStrings::Item.new(key: 'key 2', value: 'value 2'),
|
24
|
-
DotStrings::Item.new(key: 'key 3', value: 'value 3')
|
25
|
-
]
|
26
|
-
|
27
|
-
file = DotStrings::File.new(items)
|
28
|
-
|
29
|
-
assert_equal 'value 1', file['key 1'].value
|
30
|
-
assert_equal 'value 2', file['key 2'].value
|
31
|
-
assert_equal 'value 3', file['key 3'].value
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_append
|
35
|
-
file = DotStrings::File.new
|
36
|
-
file.append(DotStrings::Item.new(key: 'key 1', value: 'value 1'))
|
37
|
-
assert_equal 1, file.items.size
|
38
|
-
end
|
39
|
-
|
40
|
-
def test_to_string
|
41
|
-
file = DotStrings::File.new([
|
42
|
-
DotStrings::Item.new(comment: 'Comment 1', key: 'key 1', value: 'value 1'),
|
43
|
-
DotStrings::Item.new(comment: 'Comment 2', key: 'key 2', value: 'value 2'),
|
44
|
-
DotStrings::Item.new(comment: 'Comment 3', key: 'key 3', value: '👻'),
|
45
|
-
DotStrings::Item.new(comment: 'Comment 4', key: "\"'\t\n\r\0", value: "\"'\t\n\r\0")
|
46
|
-
])
|
47
|
-
|
48
|
-
expected = <<~'END_OF_DOCUMENT'
|
49
|
-
/* Comment 1 */
|
50
|
-
"key 1" = "value 1";
|
51
|
-
|
52
|
-
/* Comment 2 */
|
53
|
-
"key 2" = "value 2";
|
54
|
-
|
55
|
-
/* Comment 3 */
|
56
|
-
"key 3" = "👻";
|
57
|
-
|
58
|
-
/* Comment 4 */
|
59
|
-
"\"'\t\n\r\0" = "\"'\t\n\r\0";
|
60
|
-
END_OF_DOCUMENT
|
61
|
-
|
62
|
-
assert_equal expected, file.to_s
|
63
|
-
end
|
64
|
-
|
65
|
-
def test_to_string_no_comments
|
66
|
-
file = DotStrings::File.new([
|
67
|
-
DotStrings::Item.new(comment: 'Comment 1', key: 'key 1', value: 'value 1'),
|
68
|
-
DotStrings::Item.new(comment: 'Comment 2', key: 'key 2', value: 'value 2')
|
69
|
-
])
|
70
|
-
|
71
|
-
expected = <<~'END_OF_DOCUMENT'
|
72
|
-
"key 1" = "value 1";
|
73
|
-
|
74
|
-
"key 2" = "value 2";
|
75
|
-
END_OF_DOCUMENT
|
76
|
-
|
77
|
-
assert_equal expected, file.to_s(comments: false)
|
78
|
-
end
|
79
|
-
|
80
|
-
def test_to_string_can_escape_single_quotes
|
81
|
-
items = [
|
82
|
-
DotStrings::Item.new(comment: 'Comment', key: "key'", value: "value'")
|
83
|
-
]
|
84
|
-
|
85
|
-
file = DotStrings::File.new(items)
|
86
|
-
|
87
|
-
expected = <<~'END_OF_DOCUMENT'
|
88
|
-
/* Comment */
|
89
|
-
"key\'" = "value\'";
|
90
|
-
END_OF_DOCUMENT
|
91
|
-
|
92
|
-
assert_equal expected, file.to_s(escape_single_quotes: true)
|
93
|
-
end
|
94
|
-
end
|
data/test/test_item.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'helper'
|
4
|
-
|
5
|
-
class TestFile < MiniTest::Test
|
6
|
-
def test_to_s
|
7
|
-
item = DotStrings::Item.new(comment: 'Comment', key: 'key 1', value: 'value 1')
|
8
|
-
assert_equal "/* Comment */\n\"key 1\" = \"value 1\";", item.to_s
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_to_s_with_nil_comment
|
12
|
-
item = DotStrings::Item.new(comment: nil, key: 'key 1', value: 'value 1')
|
13
|
-
assert_equal '"key 1" = "value 1";', item.to_s
|
14
|
-
end
|
15
|
-
end
|