dotstrings 0.2.0 → 0.4.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: e9c320ba9bef4d63af10c9c9fd3d91ad41da99b3663538f0b89ebdc6fc780d31
4
+ data.tar.gz: 24e762927cd739f3475a8a550a751f808dd81d73292e47f7449c657edeaa88db
5
5
  SHA512:
6
- metadata.gz: a47fbb334a228e6642d7d6b3250b81ab7c7e239be8fb6ca92ba7877dfe9eb6ac0d3ba2bebe4176477afa9b825e4ce61af4a8d555b83e2a29ed6c176a6d392c90
7
- data.tar.gz: fa824b2c3c59bee05bb64d59508a6bff112a551d37d6bbc198913433fc8b332a75a17af84a5524a944126fd6e38df8bef008615df303565e729556169eb21bc8
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 "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')
@@ -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,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
 
@@ -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
 
@@ -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.4.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
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.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-07-17 00:00:00.000000000 Z
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
- rubygems_version: 3.0.1
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
@@ -1,13 +0,0 @@
1
- # EditorConfig is awesome: https://EditorConfig.org
2
-
3
- # top-most EditorConfig file
4
- root = true
5
-
6
- [*]
7
- end_of_line = lf
8
- insert_final_newline = true
9
-
10
- [{*.rb,Gemfile,Rakefile,*.yml}]
11
- charset = utf-8
12
- indent_style = space
13
- indent_size = 2
@@ -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
@@ -1,2 +0,0 @@
1
- pkg
2
- .vscode
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
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- gemspec
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
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- require 'rake/testtask'
5
- require 'rubocop/rake_task'
6
-
7
- Rake::TestTask.new
8
- RuboCop::RakeTask.new
9
-
10
- task default: :test
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
@@ -1,2 +0,0 @@
1
- /* Escaped carriage backslashes */
2
- "some\\key" = "some\\value";
@@ -1,2 +0,0 @@
1
- /* Escaped carriage returns */
2
- "some\rkey" = "some\rvalue";
@@ -1,2 +0,0 @@
1
- /* Escaped new lines */
2
- "some\nkey" = "some\nvalue";
@@ -1,2 +0,0 @@
1
- /* Escaped nil */
2
- "key\0" = "value\0";
@@ -1,2 +0,0 @@
1
- /* Escaped quotes */
2
- "some \"key\"" = "some \"value\"";
@@ -1,2 +0,0 @@
1
- /* Escaped quotes */
2
- "some \'key\'" = "some \'value\'";
@@ -1,2 +0,0 @@
1
- /* Escaped tabs */
2
- "some\tkey" = "some\tvalue";
@@ -1,2 +0,0 @@
1
- /* Unicode characters. Key is a dollar sign, value is: ⚡👻 */
2
- "\U0024" = "\U26A1\UD83D\UDC7B";
Binary file
Binary file
@@ -1,2 +0,0 @@
1
- /* Comment */
2
- "key" = "value";
@@ -1,8 +0,0 @@
1
- // Single line comment
2
- "key 1" = "value 1";
3
-
4
- /* Multi line
5
- comment */
6
- "key 2" = "value 2";
7
-
8
- "key 3" = "value 3";
data/test/helper.rb DELETED
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- gem 'minitest'
4
-
5
- require 'minitest/pride'
6
- require 'minitest/autorun'
7
-
8
- require_relative '../lib/dotstrings'
@@ -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