abroad 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +142 -0
  3. data/abroad.gemspec +25 -0
  4. data/lib/abroad/extractors/extractor.rb +46 -0
  5. data/lib/abroad/extractors/json/json_extractor.rb +17 -0
  6. data/lib/abroad/extractors/json/key_value_extractor.rb +38 -0
  7. data/lib/abroad/extractors/json.rb +8 -0
  8. data/lib/abroad/extractors/xml/android_extractor.rb +113 -0
  9. data/lib/abroad/extractors/xml/xml_extractor.rb +28 -0
  10. data/lib/abroad/extractors/xml.rb +8 -0
  11. data/lib/abroad/extractors/yaml/dotted_key_extractor.rb +40 -0
  12. data/lib/abroad/extractors/yaml/jruby_compat.rb +170 -0
  13. data/lib/abroad/extractors/yaml/rails_extractor.rb +15 -0
  14. data/lib/abroad/extractors/yaml/yaml_extractor.rb +28 -0
  15. data/lib/abroad/extractors/yaml.rb +9 -0
  16. data/lib/abroad/extractors.rb +28 -0
  17. data/lib/abroad/serializers/json/json_serializer.rb +27 -0
  18. data/lib/abroad/serializers/json/key_value_serializer.rb +20 -0
  19. data/lib/abroad/serializers/json.rb +8 -0
  20. data/lib/abroad/serializers/serializer.rb +52 -0
  21. data/lib/abroad/serializers/trie.rb +76 -0
  22. data/lib/abroad/serializers/xml/android_serializer.rb +143 -0
  23. data/lib/abroad/serializers/xml/xml_serializer.rb +23 -0
  24. data/lib/abroad/serializers/xml.rb +8 -0
  25. data/lib/abroad/serializers/yaml/rails_serializer.rb +110 -0
  26. data/lib/abroad/serializers/yaml/yaml_serializer.rb +19 -0
  27. data/lib/abroad/serializers/yaml.rb +8 -0
  28. data/lib/abroad/serializers.rb +29 -0
  29. data/lib/abroad/version.rb +3 -0
  30. data/lib/abroad.rb +37 -0
  31. data/lib/ext/htmlentities/android_xml_decoder.rb +15 -0
  32. data/lib/ext/htmlentities/android_xml_encoder.rb +23 -0
  33. data/spec/abroad_spec.rb +35 -0
  34. data/spec/extractors/json/fixtures/arrays.json +9 -0
  35. data/spec/extractors/json/fixtures/basic.json +5 -0
  36. data/spec/extractors/json/fixtures/objects.json +11 -0
  37. data/spec/extractors/json/fixtures.yml +22 -0
  38. data/spec/extractors/json/json_extractor_spec.rb +6 -0
  39. data/spec/extractors/xml/fixtures/basic_arrays.xml +9 -0
  40. data/spec/extractors/xml/fixtures/basic_plurals.xml +8 -0
  41. data/spec/extractors/xml/fixtures/basic_strings.xml +8 -0
  42. data/spec/extractors/xml/fixtures/entities.xml +4 -0
  43. data/spec/extractors/xml/fixtures/markup.xml +5 -0
  44. data/spec/extractors/xml/fixtures/newlines.xml +6 -0
  45. data/spec/extractors/xml/fixtures/quotes.xml +9 -0
  46. data/spec/extractors/xml/fixtures.yml +54 -0
  47. data/spec/extractors/xml/xml_extractor_spec.rb +6 -0
  48. data/spec/extractors/yaml/fixtures/arrays.yml +9 -0
  49. data/spec/extractors/yaml/fixtures/arrays_and_hashes.yml +29 -0
  50. data/spec/extractors/yaml/fixtures/invalid_single_quote_escape.yml +2 -0
  51. data/spec/extractors/yaml/fixtures/invalid_single_quote_escape_array.yml +3 -0
  52. data/spec/extractors/yaml/fixtures/nesting.yml +19 -0
  53. data/spec/extractors/yaml/fixtures/short.yml +2 -0
  54. data/spec/extractors/yaml/fixtures.yml +75 -0
  55. data/spec/extractors/yaml/jruby_compat_spec.rb +54 -0
  56. data/spec/extractors/yaml/yaml_extractor_spec.rb +6 -0
  57. data/spec/serializers/json/key_value_serializer_spec.rb +26 -0
  58. data/spec/serializers/xml/android_serializer_spec.rb +165 -0
  59. data/spec/serializers/yaml/rails_serializer_spec.rb +171 -0
  60. data/spec/spec_helper.rb +43 -0
  61. metadata +186 -0
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe Abroad do
4
+ describe '.extractors' do
5
+ it 'lists all the registered extractors' do
6
+ extractors = Abroad.extractors
7
+ expect(extractors).to be_a(Array)
8
+ expect(extractors).to include('yaml/rails')
9
+ end
10
+ end
11
+
12
+ describe '.serializers' do
13
+ it 'lists all the registered serializers' do
14
+ serializers = Abroad.serializers
15
+ expect(serializers).to be_a(Array)
16
+ expect(serializers).to include('yaml/rails')
17
+ end
18
+ end
19
+
20
+ describe '.extractor' do
21
+ it 'retrieves the extractor class by id' do
22
+ expect(Abroad.extractor('yaml/rails')).to eq(
23
+ Abroad::Extractors::Yaml::RailsExtractor
24
+ )
25
+ end
26
+ end
27
+
28
+ describe '.serializer' do
29
+ it 'retrieves the serializer class by id' do
30
+ expect(Abroad.serializer('yaml/rails')).to eq(
31
+ Abroad::Serializers::Yaml::RailsSerializer
32
+ )
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ {
2
+ "array1": ["1", "2", "3"],
3
+ "arrayObj": {
4
+ "array2": ["4", "5"]
5
+ },
6
+ "hello": "cool string",
7
+ "foo.bar": "baz",
8
+ "jelly.beans": "popcorn"
9
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "hello": "cool string",
3
+ "foo.bar": "baz",
4
+ "jelly.beans": "popcorn"
5
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "smartling" : {
3
+ "translate_paths" : ["/*", "/*/*"],
4
+ "source_key_paths" : ["/{*}"],
5
+ "variants_enabled" : true,
6
+ "placeholder_format_custom" : ["%s"]
7
+ },
8
+ "hello": "cool string",
9
+ "foo.bar": "baz",
10
+ "jelly.beans": "popcorn"
11
+ }
@@ -0,0 +1,22 @@
1
+ :json/key-value:
2
+ basic.json:
3
+ - key: foo.bar
4
+ string: baz
5
+ - key: hello
6
+ string: cool string
7
+ - key: jelly.beans
8
+ string: popcorn
9
+ objects.json:
10
+ - key: foo.bar
11
+ string: baz
12
+ - key: hello
13
+ string: cool string
14
+ - key: jelly.beans
15
+ string: popcorn
16
+ arrays.json:
17
+ - key: foo.bar
18
+ string: baz
19
+ - key: hello
20
+ string: cool string
21
+ - key: jelly.beans
22
+ string: popcorn
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'JsonExtractor' do
4
+ fixture_dir = File.expand_path('./', File.dirname(__FILE__))
5
+ it_behaves_like 'a fixture-based extractor', fixture_dir, Abroad::Extractors::Json
6
+ end
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <string-array name="captains">
4
+ <item>Janeway</item>
5
+ <item>Sisko</item>
6
+ <item>Picard</item>
7
+ <item>Kirk</item>
8
+ </string-array>
9
+ </resources>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <plurals name="horses">
4
+ <item quantity="zero">There are no horses</item>
5
+ <item quantity="one">There is one horse</item>
6
+ <item quantity="other">There are %d horses</item>
7
+ </plurals>
8
+ </resources>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <resources>
3
+ <string name="foobar">baz</string>
4
+ <string name="password_length_too_short">Password is too short</string>
5
+ <string name="password_length_too_long">Password is too long</string>
6
+ <string name="password_empty">Please enter your password.</string>
7
+ <string name="username_empty">Please enter your email address.</string>
8
+ </resources>
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <resources>
3
+ <string name="states">Alaska &amp; Washington</string>
4
+ </resources>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <resources>
3
+ <string name="internal_markup">I <b>have</b> <a href="foo">internal</a> markup</string>
4
+ <string name="quoted_markup">"I <b>have</b> <a href="foo">quoted</a> markup"</string>
5
+ </resources>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <resources>
3
+ <string name="foobar">baz</string>
4
+ <string name="password_length_too_short">Password is
5
+ too short</string>
6
+ </resources>
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <resources>
3
+ <string name="quotes">"I have quotes"</string>
4
+ <string name="leading_space">" I have a leading space"</string>
5
+ <string name="internal_quotes">"I have \"internal\" quotes"</string>
6
+ <string name="apostrophes">That\'s the ticket</string>
7
+ <string name="apostrophes_in_quotes">"That's the ticket"</string>
8
+ <string name="escaped_apostrophes_in_quotes">"That\'s the ticket"</string>
9
+ </resources>
@@ -0,0 +1,54 @@
1
+ :xml/android:
2
+ basic_strings.xml:
3
+ - key: foobar
4
+ string: baz
5
+ - key: password_length_too_short
6
+ string: Password is too short
7
+ - key: password_length_too_long
8
+ string: Password is too long
9
+ - key: password_empty
10
+ string: Please enter your password.
11
+ - key: username_empty
12
+ string: Please enter your email address.
13
+ basic_arrays.xml:
14
+ - key: captains.0
15
+ string: Janeway
16
+ - key: captains.1
17
+ string: Sisko
18
+ - key: captains.2
19
+ string: Picard
20
+ - key: captains.3
21
+ string: Kirk
22
+ basic_plurals.xml:
23
+ - key: horses.zero
24
+ string: There are no horses
25
+ - key: horses.one
26
+ string: There is one horse
27
+ - key: horses.other
28
+ string: There are %d horses
29
+ quotes.xml:
30
+ - key: quotes
31
+ string: I have quotes
32
+ - key: leading_space
33
+ string: " I have a leading space"
34
+ - key: internal_quotes
35
+ string: I have "internal" quotes
36
+ - key: apostrophes
37
+ string: That's the ticket
38
+ - key: apostrophes_in_quotes
39
+ string: That's the ticket
40
+ - key: escaped_apostrophes_in_quotes
41
+ string: That's the ticket
42
+ markup.xml:
43
+ - key: internal_markup
44
+ string: I <b>have</b> <a href="foo">internal</a> markup
45
+ - key: quoted_markup
46
+ string: I <b>have</b> <a href="foo">quoted</a> markup
47
+ newlines.xml:
48
+ - key: foobar
49
+ string: baz
50
+ - key: password_length_too_short
51
+ string: "Password is\ntoo short"
52
+ entities.xml:
53
+ - key: states
54
+ string: "Alaska & Washington"
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'XmlExtractor' do
4
+ fixture_dir = File.expand_path('./', File.dirname(__FILE__))
5
+ it_behaves_like 'a fixture-based extractor', fixture_dir, Abroad::Extractors::Xml
6
+ end
@@ -0,0 +1,9 @@
1
+ en:
2
+ jobs:
3
+ benefits:
4
+ - Benefits to write home about
5
+ - Stress-free commute
6
+ - Brand-new gadgets
7
+ other:
8
+ - Stay happy and healthy
9
+ - Playtime anytime
@@ -0,0 +1,29 @@
1
+ en:
2
+ jobs:
3
+ benefits:
4
+ -
5
+ title: Benefits to write home about
6
+ body:
7
+ - Competitive salaries and bonuses
8
+ - Medical, dental, vision, and life insurance plans
9
+ -
10
+ title: Stress-free commute
11
+ body:
12
+ - Downtown SF location right next to BART and MUNI lines
13
+ - Free cabs and meals for those late nights
14
+ -
15
+ title: Brand-new gadgets
16
+ body:
17
+ - Pick out a new Mac or PC desktop or laptop
18
+ - Big monitors, fancy headphones, and more
19
+ -
20
+ title: Stay happy and healthy
21
+ body:
22
+ - Catered lunches and a pantry with every snack, drink, and Bi-Rite meal
23
+ - Gym membership at the Sports Club LA (2 blocks from the office)
24
+ -
25
+ title: Playtime anytime
26
+ body:
27
+ - Unlimited paid time off
28
+ - A game room with video games, board games, foosball, ping-pong, and shuffleboard
29
+ - A Culture Team behind office happy hours and Hawai'i holiday parties
@@ -0,0 +1,2 @@
1
+ foo:
2
+ bar: "baz\'boo"
@@ -0,0 +1,3 @@
1
+ foo:
2
+ bar:
3
+ - "baz\'boo"
@@ -0,0 +1,19 @@
1
+ en:
2
+ activerecord:
3
+ attributes:
4
+ user:
5
+ unique_name: "Username"
6
+ password: "Password"
7
+ email_address: "Email address"
8
+ email_address:
9
+ address: "Email address"
10
+ testimonial:
11
+ original_text: "Your Story"
12
+ errors:
13
+ custom:
14
+ user:
15
+ uniqueness_of_unique_name: has already been taken
16
+ password_does_not_match_unique_name: cannot match username
17
+ cannot_disable_if_full_access: Cannot disable a user who has full access
18
+ current_password_blank: Please enter your current password
19
+ current_password_mismatch: The password you entered does not match our records
@@ -0,0 +1,2 @@
1
+ foo:
2
+ bar: baz
@@ -0,0 +1,75 @@
1
+ :yaml/dotted-key:
2
+ invalid_single_quote_escape_array.yml:
3
+ - key: foo.bar.0
4
+ string: baz'boo
5
+ invalid_single_quote_escape.yml:
6
+ - key: foo.bar
7
+ string: baz'boo
8
+ short.yml:
9
+ - key: foo.bar
10
+ string: baz
11
+ nesting.yml:
12
+ - key: en.activerecord.attributes.user.unique_name
13
+ string: Username
14
+ - key: en.activerecord.attributes.user.password
15
+ string: Password
16
+ - key: en.activerecord.attributes.user.email_address
17
+ string: Email address
18
+ - key: en.activerecord.attributes.email_address.address
19
+ string: Email address
20
+ - key: en.activerecord.attributes.testimonial.original_text
21
+ string: Your Story
22
+ - key: en.activerecord.errors.custom.user.uniqueness_of_unique_name
23
+ string: has already been taken
24
+ - key: en.activerecord.errors.custom.user.password_does_not_match_unique_name
25
+ string: cannot match username
26
+ - key: en.activerecord.errors.custom.user.cannot_disable_if_full_access
27
+ string: Cannot disable a user who has full access
28
+ - key: en.activerecord.errors.custom.user.current_password_blank
29
+ string: Please enter your current password
30
+ - key: en.activerecord.errors.custom.user.current_password_mismatch
31
+ string: The password you entered does not match our records
32
+ arrays.yml:
33
+ - key: en.jobs.benefits.0
34
+ string: Benefits to write home about
35
+ - key: en.jobs.benefits.1
36
+ string: Stress-free commute
37
+ - key: en.jobs.benefits.2
38
+ string: Brand-new gadgets
39
+ - key: en.jobs.other.0
40
+ string: Stay happy and healthy
41
+ - key: en.jobs.other.1
42
+ string: Playtime anytime
43
+ arrays_and_hashes.yml:
44
+ - key: en.jobs.benefits.0.title
45
+ string: Benefits to write home about
46
+ - key: en.jobs.benefits.0.body.0
47
+ string: Competitive salaries and bonuses
48
+ - key: en.jobs.benefits.0.body.1
49
+ string: Medical, dental, vision, and life insurance plans
50
+ - key: en.jobs.benefits.1.title
51
+ string: Stress-free commute
52
+ - key: en.jobs.benefits.1.body.0
53
+ string: Downtown SF location right next to BART and MUNI lines
54
+ - key: en.jobs.benefits.1.body.1
55
+ string: Free cabs and meals for those late nights
56
+ - key: en.jobs.benefits.2.title
57
+ string: Brand-new gadgets
58
+ - key: en.jobs.benefits.2.body.0
59
+ string: Pick out a new Mac or PC desktop or laptop
60
+ - key: en.jobs.benefits.2.body.1
61
+ string: Big monitors, fancy headphones, and more
62
+ - key: en.jobs.benefits.3.title
63
+ string: Stay happy and healthy
64
+ - key: en.jobs.benefits.3.body.0
65
+ string: Catered lunches and a pantry with every snack, drink, and Bi-Rite meal
66
+ - key: en.jobs.benefits.3.body.1
67
+ string: Gym membership at the Sports Club LA (2 blocks from the office)
68
+ - key: en.jobs.benefits.4.title
69
+ string: Playtime anytime
70
+ - key: en.jobs.benefits.4.body.0
71
+ string: Unlimited paid time off
72
+ - key: en.jobs.benefits.4.body.1
73
+ string: A game room with video games, board games, foosball, ping-pong, and shuffleboard
74
+ - key: en.jobs.benefits.4.body.2
75
+ string: A Culture Team behind office happy hours and Hawai'i holiday parties
@@ -0,0 +1,54 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ if Abroad.jruby?
6
+ require 'abroad/extractors/yaml/jruby_compat'
7
+
8
+ describe 'JRubyCompat' do
9
+ let(:compat) { Abroad::Extractors::Yaml::JRubyCompat }
10
+
11
+ describe 'clean' do
12
+ it 'replaces escaped single quotes in key/value pairs' do
13
+ yaml = "foo:\n" +
14
+ " bar: \"baz\\'boo\""
15
+
16
+ expect { YAML.load(yaml) }.to raise_error(Psych::SyntaxError)
17
+ expect(YAML.load(compat.clean(yaml))).to eq({
18
+ 'foo' => { 'bar' => "baz'boo" }
19
+ })
20
+ end
21
+
22
+ it 'replaces escaped single quotes in array elements' do
23
+ yaml = "foo:\n" +
24
+ " - abc\n" +
25
+ " - \"def\\'ghi\""
26
+
27
+ expect { YAML.load(yaml) }.to raise_error(Psych::SyntaxError)
28
+ expect(YAML.load(compat.clean(yaml))).to eq({
29
+ 'foo' => ['abc', "def'ghi"]
30
+ })
31
+ end
32
+
33
+ it 'does not replace escaped single quotes that occur outside of double quotes' do
34
+ yaml = "foo:\n" +
35
+ " bar: abc\\'def"
36
+
37
+ expect { YAML.load(yaml) }.to_not raise_error
38
+ expect(YAML.load(compat.clean(yaml))).to eq({
39
+ 'foo' => { 'bar' => "abc\\'def" }
40
+ })
41
+ end
42
+
43
+ it 'does not replace escaped single quotes that occur outside of double quotes in arrays' do
44
+ yaml = "foo:\n" +
45
+ " - def\\'ghi"
46
+
47
+ expect { YAML.load(yaml) }.to_not raise_error
48
+ expect(YAML.load(compat.clean(yaml))).to eq({
49
+ 'foo' => ["def\\'ghi"]
50
+ })
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'YamlExtractor' do
4
+ fixture_dir = File.expand_path('./', File.dirname(__FILE__))
5
+ it_behaves_like 'a fixture-based extractor', fixture_dir, Abroad::Extractors::Yaml
6
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ include Abroad::Serializers
4
+
5
+ describe Json::KeyValueSerializer do
6
+ let(:stream) { StringIO.new }
7
+ let(:locale) { 'fr-FR' }
8
+
9
+ let(:serializer) do
10
+ Json::KeyValueSerializer.new(stream, locale)
11
+ end
12
+
13
+ def serialize
14
+ yield
15
+ serializer.flush
16
+ stream.string
17
+ end
18
+
19
+ it 'writes key/value pairs' do
20
+ result = serialize do
21
+ serializer.write_key_value('foo', 'bar')
22
+ end
23
+
24
+ expect(result).to eq('{"foo":"bar"}')
25
+ end
26
+ end
@@ -0,0 +1,165 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+
4
+ include Abroad::Serializers
5
+
6
+ # NOTE: The use of YAML in these specs is only to make writing multi-line
7
+ # indented strings easier to read and write
8
+ describe Xml::AndroidSerializer do
9
+ let(:stream) { StringIO.new }
10
+ let(:locale) { 'fr-FR' }
11
+
12
+ let(:serializer) do
13
+ Xml::AndroidSerializer.new(stream, locale)
14
+ end
15
+
16
+ def serialize
17
+ yield
18
+ serializer.flush
19
+ stream.string
20
+ end
21
+
22
+ it 'writes key/value pairs' do
23
+ result = serialize do
24
+ serializer.write_key_value('foo', 'bar')
25
+ end
26
+
27
+ expect(result).to eq(YAML.load(<<-EOM
28
+ |
29
+ <?xml version="1.0" encoding="UTF-8"?>
30
+ <resources>
31
+ <string name="foo">bar</string>
32
+ </resources>
33
+ EOM
34
+ ).strip)
35
+ end
36
+
37
+ it 'detects and writes plurals' do
38
+ result = serialize do
39
+ serializer.write_key_value('horses.one', 'There is one horse')
40
+ serializer.write_key_value('horses.other', 'There are %d horses')
41
+ end
42
+
43
+ expect(result).to eq(YAML.load(<<-EOM
44
+ |
45
+ <?xml version="1.0" encoding="UTF-8"?>
46
+ <resources>
47
+ <plurals name="horses">
48
+ <item quantity="one">There is one horse</item>
49
+ <item quantity="other">There are %d horses</item>
50
+ </plurals>
51
+ </resources>
52
+ EOM
53
+ ).strip)
54
+ end
55
+
56
+ it 'detects and writes arrays in any order' do
57
+ result = serialize do
58
+ serializer.write_key_value('captains.1', 'Kirk')
59
+ serializer.write_key_value('captains.3', 'Sisko')
60
+ serializer.write_key_value('captains.0', 'Janeway')
61
+ serializer.write_key_value('captains.2', 'Picard')
62
+ end
63
+
64
+ expect(result).to eq(YAML.load(<<-EOM
65
+ |
66
+ <?xml version="1.0" encoding="UTF-8"?>
67
+ <resources>
68
+ <string-array name="captains">
69
+ <item>Janeway</item>
70
+ <item>Kirk</item>
71
+ <item>Picard</item>
72
+ <item>Sisko</item>
73
+ </string-array>
74
+ </resources>
75
+ EOM
76
+ ).strip)
77
+ end
78
+
79
+ it "doesn't escape entities" do
80
+ result = serialize do
81
+ serializer.write_key_value('states', "Alaska & Hawai'i")
82
+ end
83
+
84
+ expect(result).to eq(YAML.load(<<-EOM
85
+ |
86
+ <?xml version="1.0" encoding="UTF-8"?>
87
+ <resources>
88
+ <string name="states">Alaska &amp; Hawai\\'i</string>
89
+ </resources>
90
+ EOM
91
+ ).strip)
92
+ end
93
+
94
+ it "doesn't escape html elements" do
95
+ result = serialize do
96
+ serializer.write_key_value('captain', "<b>Jean Luc</b> Picard")
97
+ end
98
+
99
+ expect(result).to eq(YAML.load(<<-EOM
100
+ |
101
+ <?xml version="1.0" encoding="UTF-8"?>
102
+ <resources>
103
+ <string name="captain"><b>Jean Luc</b> Picard</string>
104
+ </resources>
105
+ EOM
106
+ ).strip)
107
+ end
108
+
109
+ it 'escapes double quotes' do
110
+ result = serialize do
111
+ serializer.write_key_value('wow', 'And I said "cool"')
112
+ end
113
+
114
+ expect(result).to eq(YAML.load(<<-EOM
115
+ |
116
+ <?xml version="1.0" encoding="UTF-8"?>
117
+ <resources>
118
+ <string name="wow">And I said \\"cool\\"</string>
119
+ </resources>
120
+ EOM
121
+ ).strip)
122
+ end
123
+
124
+ it 'escapes double quotes at the beginning of a string' do
125
+ result = serialize do
126
+ serializer.write_key_value('wow', '"Elvis" is cool')
127
+ end
128
+
129
+ expect(result).to eq(YAML.load(<<-EOM
130
+ |
131
+ <?xml version="1.0" encoding="UTF-8"?>
132
+ <resources>
133
+ <string name="wow">\\"Elvis\\" is cool</string>
134
+ </resources>
135
+ EOM
136
+ ).strip)
137
+ end
138
+
139
+ it 'writes a mixture of all types of string' do
140
+ result = serialize do
141
+ serializer.write_key_value('justaplural.many', 'Many plurals')
142
+ serializer.write_key_value('justanarray.1', 'Second in line')
143
+ serializer.write_key_value('justanarray.0', 'First in line')
144
+ serializer.write_key_value('justastring', "I'm very basic")
145
+ serializer.write_key_value('justaplural.one', 'One plural')
146
+ end
147
+
148
+ expect(result).to eq(YAML.load(<<-EOM
149
+ |
150
+ <?xml version="1.0" encoding="UTF-8"?>
151
+ <resources>
152
+ <string name="justastring">I\\'m very basic</string>
153
+ <plurals name="justaplural">
154
+ <item quantity="many">Many plurals</item>
155
+ <item quantity="one">One plural</item>
156
+ </plurals>
157
+ <string-array name="justanarray">
158
+ <item>First in line</item>
159
+ <item>Second in line</item>
160
+ </string-array>
161
+ </resources>
162
+ EOM
163
+ ).strip)
164
+ end
165
+ end