dotstrings 0.2.0 → 0.3.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 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