dotstrings 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 605ff8ed35fcfcbd91f2fc33a4b53e69b614aab962de1c32c1d616f957ee1916
4
- data.tar.gz: dddf00d461a893a4ff4e97c04fcc87617241e42189d0284b22e4ab98313ed25a
3
+ metadata.gz: a7f215ea68d4b6ce65de6f15811800b976eb722b89a4618bce4503338508df51
4
+ data.tar.gz: 51a72c22c7233b00df29f97d876abb3e59517de4bf0b78797ab8897d122250fe
5
5
  SHA512:
6
- metadata.gz: a47fbb334a228e6642d7d6b3250b81ab7c7e239be8fb6ca92ba7877dfe9eb6ac0d3ba2bebe4176477afa9b825e4ce61af4a8d555b83e2a29ed6c176a6d392c90
7
- data.tar.gz: fa824b2c3c59bee05bb64d59508a6bff112a551d37d6bbc198913433fc8b332a75a17af84a5524a944126fd6e38df8bef008615df303565e729556169eb21bc8
6
+ metadata.gz: 0d9247c103eb79e3e908a55af5661de97cae316cc36660c7c872a869f077a9875060eab7bab7caa0a9aa8c2ef82d6ce7c5b9acede49fa1227790b4aad53b205d
7
+ data.tar.gz: af144c8d6b3f9f552fc71db2df31db95f1189575fa8eb9e2c5f97ab0a15234024bcd97692218be4bbd04f7352f6a3d63966b4ff4948df84379158733583920ad
data/.gitignore CHANGED
@@ -1,2 +1,5 @@
1
1
  pkg
2
2
  .vscode
3
+ coverage
4
+ doc
5
+ .yardoc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.3.0] - 2022-08-07
4
+ ### Changed
5
+ * Improved unicode code point parsing and validation.
6
+ * Added `DotStrings::File#sort`, `DotStrings::File#sort!`, and `DotStrings::File#delete_if` methods.
7
+ * Improved documentation.
8
+
3
9
  ## [v0.2.0] - 2022-07-17
4
10
  ### Changed
5
11
  * Made some state transitions more strict.
data/Gemfile.lock CHANGED
@@ -1,12 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dotstrings (0.2.0)
4
+ dotstrings (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  ast (2.4.2)
10
+ docile (1.4.0)
10
11
  minitest (5.15.0)
11
12
  parallel (1.22.1)
12
13
  parser (3.1.2.0)
@@ -31,6 +32,12 @@ GEM
31
32
  rubocop-rake (0.6.0)
32
33
  rubocop (~> 1.0)
33
34
  ruby-progressbar (1.11.0)
35
+ simplecov (0.21.2)
36
+ docile (~> 1.1)
37
+ simplecov-html (~> 0.11)
38
+ simplecov_json_formatter (~> 0.1)
39
+ simplecov-html (0.12.3)
40
+ simplecov_json_formatter (0.1.4)
34
41
  unicode-display_width (2.2.0)
35
42
 
36
43
  PLATFORMS
@@ -44,6 +51,7 @@ DEPENDENCIES
44
51
  rubocop
45
52
  rubocop-minitest
46
53
  rubocop-rake
54
+ simplecov
47
55
 
48
56
  BUNDLED WITH
49
57
  2.2.18
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 "dotstrings"
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 is invalid.
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/dotstrings.gemspec CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
22
22
  s.add_development_dependency 'rubocop'
23
23
  s.add_development_dependency 'rubocop-minitest'
24
24
  s.add_development_dependency 'rubocop-rake'
25
+ s.add_development_dependency 'simplecov'
25
26
 
26
27
  s.required_ruby_version = '>= 2.5.0'
27
28
  s.metadata['rubygems_mfa_required'] = 'true'
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DotStrings
4
+ ##
5
+ # Class for errors raised by the parser.
4
6
  class ParsingError < RuntimeError
5
7
  end
6
8
  end
@@ -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,85 @@ 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
+ # Serializes the file to a string.
136
+ #
137
+ # @param escape_single_quotes [Boolean] whether to escape single quotes.
138
+ # @param comments [Boolean] whether to include comments.
51
139
  def to_s(escape_single_quotes: false, comments: true)
52
140
  result = []
53
141
 
@@ -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,11 @@ module DotStrings
10
12
  @value = value
11
13
  end
12
14
 
15
+ ##
16
+ # Serializes the item to string.
17
+ #
18
+ # @param escape_single_quotes [Boolean] Whether to escape single quotes.
19
+ # @param include_comment [Boolean] Whether to include the comment.
13
20
  def to_s(escape_single_quotes: false, include_comment: true)
14
21
  result = []
15
22
 
@@ -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 Style/GuardClause
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 @unicode_buffer.length == 4
213
- codepoint = @unicode_buffer.join.hex
219
+ # Check if we have enough digits to form a codepoint.
220
+ return if @unicode_buffer.length < 4
214
221
 
215
- if codepoint >= 0xD800 && codepoint <= 0xDBFF
216
- @high_surrogate = codepoint
217
- @state = STATE_UNICODE_SURROGATE
218
- elsif codepoint >= 0xDC00 && codepoint <= 0xDFFF
219
- character = ((@high_surrogate - 0xD800) * 0x400) + (codepoint - 0xDC00) + 0x10000
220
- block.call(character.chr('UTF-8'))
221
- else
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
- # Clear buffer after codepoint is parsed
226
- @unicode_buffer.clear
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 Style/GuardClause
257
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
230
258
 
231
259
  def update_position(ch)
232
260
  @offset += 1
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DotStrings
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
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
@@ -0,0 +1 @@
1
+ "key" = "\UDC7B\UD83D";
@@ -0,0 +1 @@
1
+ "key" = "\UD83D\UD83D";
@@ -0,0 +1 @@
1
+ "key" = "\UD83D";
@@ -0,0 +1 @@
1
+ "key" = "\UD83D\U26A1";
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'helper'
3
+ require_relative 'test_helper'
4
4
 
5
5
  class TestDotStrings < MiniTest::Test
6
6
  def test_parse_can_parse_valid_files
@@ -81,6 +81,25 @@ class TestDotStrings < MiniTest::Test
81
81
  assert_equal '⚡👻', file.items[0].value
82
82
  end
83
83
 
84
+ def test_raises_error_when_bad_surrogate_pair_is_found
85
+ # rubocop:disable Layout/LineLength
86
+ test_cases = {
87
+ 'escaped_unicode~bad_surrogate_order.strings' => 'Found a low surrogate code point before a high surrogate at line 1, column 15 (offset: 14)',
88
+ 'escaped_unicode~duplicated_high_surrogate.strings' => 'Found a high surrogate code point after another high surrogate at line 1, column 21 (offset: 20)',
89
+ 'escaped_unicode~incomplete_surrogate_pair.strings' => 'Unexpected character \'"\', expecting another unicode codepoint at line 1, column 16 (offset: 15)',
90
+ 'escaped_unicode~non_surrogate_after_high_surrogate.strings' => 'Invalid unicode codepoint \'\U26A1\' after a high surrogate code point at line 1, column 21 (offset: 20)'
91
+ }
92
+ # rubocop:enable Layout/LineLength
93
+
94
+ test_cases.each do |filename, error_message|
95
+ error = assert_raises DotStrings::ParsingError do
96
+ DotStrings.parse_file("test/fixtures/#{filename}")
97
+ end
98
+
99
+ assert_equal error_message, error.message
100
+ end
101
+ end
102
+
84
103
  def test_can_parse_utf16le_files_with_bom
85
104
  file = DotStrings.parse_file('test/fixtures/utf16le_bom.strings')
86
105
 
data/test/test_file.rb CHANGED
@@ -1,8 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'helper'
3
+ require_relative 'test_helper'
4
4
 
5
5
  class TestFile < MiniTest::Test
6
+ def test_sort
7
+ file = DotStrings::File.new([
8
+ DotStrings::Item.new(key: 'key 3', value: 'value 3'),
9
+ DotStrings::Item.new(key: 'key 2', value: 'value 2'),
10
+ DotStrings::Item.new(key: 'key 1', value: 'value 1')
11
+ ])
12
+
13
+ sorted = file.sort
14
+ assert_equal ['key 1', 'key 2', 'key 3'], sorted.keys
15
+ end
16
+
6
17
  def test_delete
7
18
  items = [
8
19
  DotStrings::Item.new(key: 'key 1', value: 'value 1'),
@@ -17,6 +28,17 @@ class TestFile < MiniTest::Test
17
28
  assert_equal ['key 1', 'key 3'], file.keys
18
29
  end
19
30
 
31
+ def test_delete_if
32
+ file = DotStrings::File.new([
33
+ DotStrings::Item.new(key: 'key 1', value: 'value 1'),
34
+ DotStrings::Item.new(key: 'key 2', value: 'value 2'),
35
+ DotStrings::Item.new(key: 'key 3', value: 'value 3')
36
+ ])
37
+
38
+ file.delete_if { |item| item.key == 'key 2' }
39
+ assert_equal ['key 1', 'key 3'], file.keys
40
+ end
41
+
20
42
  def test_access_by_key
21
43
  items = [
22
44
  DotStrings::Item.new(key: 'key 1', value: 'value 1'),
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- gem 'minitest'
3
+ require 'simplecov'
4
+ SimpleCov.start
4
5
 
6
+ require 'minitest'
5
7
  require 'minitest/pride'
6
8
  require 'minitest/autorun'
7
9
 
data/test/test_item.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'helper'
3
+ require_relative 'test_helper'
4
4
 
5
5
  class TestFile < MiniTest::Test
6
6
  def test_to_s
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'test_helper'
4
+
5
+ class TestParser < MiniTest::Test
6
+ def test_handles_extraneous_characters_at_start_of_file
7
+ error = assert_raises DotStrings::ParsingError do
8
+ parser = DotStrings::Parser.new
9
+ parser << '$'
10
+ end
11
+
12
+ assert_equal "Unexpected character '$' at line 1, column 1 (offset: 0)", error.message
13
+ end
14
+
15
+ def test_handles_malformed_comments
16
+ error = assert_raises DotStrings::ParsingError do
17
+ parser = DotStrings::Parser.new
18
+ parser << '/@ test'
19
+ end
20
+
21
+ assert_equal "Unexpected character '@' at line 1, column 2 (offset: 1)", error.message
22
+ end
23
+
24
+ def test_raises_error_when_escaping_invalid_character
25
+ error = assert_raises DotStrings::ParsingError do
26
+ parser = DotStrings::Parser.new
27
+ parser << '"\\z" = "value";'
28
+ end
29
+
30
+ assert_equal "Unexpected character 'z' at line 1, column 3 (offset: 2)", error.message
31
+ end
32
+
33
+ def test_raises_error_when_items_are_not_separated_by_semicolon
34
+ error = assert_raises DotStrings::ParsingError do
35
+ parser = DotStrings::Parser.new
36
+ parser << '"key_1" = "value_1" "key_2" = "value_2"'
37
+ end
38
+
39
+ assert_equal "Unexpected character '\"', expecting ';' at line 1, column 21 (offset: 20)", error.message
40
+ end
41
+
42
+ def test_raises_error_if_low_surrogate_is_not_formatted_correctly
43
+ error = assert_raises DotStrings::ParsingError do
44
+ parser = DotStrings::Parser.new
45
+ parser << '"key" = "\UD83D\$DC7B";'
46
+ end
47
+
48
+ assert_equal "Unexpected character '$', expecting 'U' at line 1, column 17 (offset: 16)", error.message
49
+ end
50
+ 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.2.0
4
+ version: 0.3.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-07-17 00:00:00.000000000 Z
11
+ date: 2022-08-07 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:
@@ -127,14 +141,19 @@ files:
127
141
  - test/fixtures/escaped_single_quotes.strings
128
142
  - test/fixtures/escaped_tabs.strings
129
143
  - test/fixtures/escaped_unicode.strings
144
+ - test/fixtures/escaped_unicode~bad_surrogate_order.strings
145
+ - test/fixtures/escaped_unicode~duplicated_high_surrogate.strings
146
+ - test/fixtures/escaped_unicode~incomplete_surrogate_pair.strings
147
+ - test/fixtures/escaped_unicode~non_surrogate_after_high_surrogate.strings
130
148
  - test/fixtures/utf16be_bom.strings
131
149
  - test/fixtures/utf16le_bom.strings
132
150
  - test/fixtures/utf8_bom.strings
133
151
  - test/fixtures/valid.strings
134
- - test/helper.rb
135
152
  - test/test_dotstrings.rb
136
153
  - test/test_file.rb
154
+ - test/test_helper.rb
137
155
  - test/test_item.rb
156
+ - test/test_parser.rb
138
157
  homepage: https://github.com/raymondjavaxx/dotstrings
139
158
  licenses:
140
159
  - MIT
@@ -168,11 +187,16 @@ test_files:
168
187
  - test/fixtures/escaped_single_quotes.strings
169
188
  - test/fixtures/escaped_tabs.strings
170
189
  - test/fixtures/escaped_unicode.strings
190
+ - test/fixtures/escaped_unicode~bad_surrogate_order.strings
191
+ - test/fixtures/escaped_unicode~duplicated_high_surrogate.strings
192
+ - test/fixtures/escaped_unicode~incomplete_surrogate_pair.strings
193
+ - test/fixtures/escaped_unicode~non_surrogate_after_high_surrogate.strings
171
194
  - test/fixtures/utf16be_bom.strings
172
195
  - test/fixtures/utf16le_bom.strings
173
196
  - test/fixtures/utf8_bom.strings
174
197
  - test/fixtures/valid.strings
175
- - test/helper.rb
176
198
  - test/test_dotstrings.rb
177
199
  - test/test_file.rb
200
+ - test/test_helper.rb
178
201
  - test/test_item.rb
202
+ - test/test_parser.rb