twine 0.9.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +56 -69
  3. data/lib/twine.rb +11 -3
  4. data/lib/twine/cli.rb +375 -155
  5. data/lib/twine/formatters.rb +0 -5
  6. data/lib/twine/formatters/abstract.rb +43 -43
  7. data/lib/twine/formatters/android.rb +58 -59
  8. data/lib/twine/formatters/apple.rb +3 -3
  9. data/lib/twine/formatters/django.rb +15 -21
  10. data/lib/twine/formatters/flash.rb +17 -20
  11. data/lib/twine/formatters/gettext.rb +11 -15
  12. data/lib/twine/formatters/jquery.rb +8 -11
  13. data/lib/twine/formatters/tizen.rb +4 -4
  14. data/lib/twine/output_processor.rb +15 -15
  15. data/lib/twine/placeholders.rb +26 -6
  16. data/lib/twine/runner.rb +95 -95
  17. data/lib/twine/{stringsfile.rb → twine_file.rb} +53 -48
  18. data/lib/twine/version.rb +1 -1
  19. data/test/{command_test_case.rb → command_test.rb} +5 -5
  20. data/test/fixtures/{consume_loc_drop.zip → consume_localization_archive.zip} +0 -0
  21. data/test/fixtures/formatter_django.po +3 -1
  22. data/test/test_abstract_formatter.rb +40 -40
  23. data/test/test_cli.rb +313 -211
  24. data/test/test_consume_localization_archive.rb +27 -0
  25. data/test/{test_consume_string_file.rb → test_consume_localization_file.rb} +19 -19
  26. data/test/test_formatters.rb +108 -43
  27. data/test/{test_generate_all_string_files.rb → test_generate_all_localization_files.rb} +18 -18
  28. data/test/{test_generate_loc_drop.rb → test_generate_localization_archive.rb} +14 -14
  29. data/test/{test_generate_string_file.rb → test_generate_localization_file.rb} +18 -18
  30. data/test/test_output_processor.rb +26 -26
  31. data/test/test_placeholders.rb +44 -9
  32. data/test/test_twine_definition.rb +111 -0
  33. data/test/test_twine_file.rb +58 -0
  34. data/test/test_validate_twine_file.rb +61 -0
  35. data/test/twine_file_dsl.rb +12 -12
  36. data/test/{twine_test_case.rb → twine_test.rb} +1 -1
  37. metadata +23 -23
  38. data/test/test_consume_loc_drop.rb +0 -27
  39. data/test/test_strings_file.rb +0 -58
  40. data/test/test_strings_row.rb +0 -47
  41. data/test/test_validate_strings_file.rb +0 -61
@@ -1,6 +1,6 @@
1
- require 'command_test_case'
1
+ require 'command_test'
2
2
 
3
- class TestGenerateAllStringFiles < CommandTestCase
3
+ class TestGenerateAllLocalizationFiles < CommandTest
4
4
  def new_runner(create_folders, twine_file = nil)
5
5
  options = {}
6
6
  options[:output_path] = @output_dir
@@ -10,7 +10,7 @@ class TestGenerateAllStringFiles < CommandTestCase
10
10
  unless twine_file
11
11
  twine_file = build_twine_file 'en', 'es' do
12
12
  add_section 'Section' do
13
- add_row key: 'value'
13
+ add_definition key: 'value'
14
14
  end
15
15
  end
16
16
  end
@@ -18,57 +18,57 @@ class TestGenerateAllStringFiles < CommandTestCase
18
18
  Twine::Runner.new(options, twine_file)
19
19
  end
20
20
 
21
- class TestDoNotCreateFolders < TestGenerateAllStringFiles
21
+ class TestDoNotCreateFolders < TestGenerateAllLocalizationFiles
22
22
  def new_runner(twine_file = nil)
23
23
  super(false, twine_file)
24
24
  end
25
25
 
26
26
  def test_fails_if_output_folder_does_not_exist
27
27
  assert_raises Twine::Error do
28
- new_runner.generate_all_string_files
28
+ new_runner.generate_all_localization_files
29
29
  end
30
30
  end
31
31
 
32
32
  def test_does_not_create_language_folders
33
33
  Dir.mkdir File.join @output_dir, 'en.lproj'
34
- new_runner.generate_all_string_files
34
+ new_runner.generate_all_localization_files
35
35
  refute File.exists?(File.join(@output_dir, 'es.lproj')), "language folder should not be created"
36
36
  end
37
37
 
38
38
  def test_prints_empty_file_warnings
39
39
  Dir.mkdir File.join @output_dir, 'en.lproj'
40
40
  empty_twine_file = build_twine_file('en') {}
41
- new_runner(empty_twine_file).generate_all_string_files
41
+ new_runner(empty_twine_file).generate_all_localization_files
42
42
  assert_match "Skipping file at path", Twine::stderr.string
43
43
  end
44
44
  end
45
45
 
46
- class TestCreateFolders < TestGenerateAllStringFiles
46
+ class TestCreateFolders < TestGenerateAllLocalizationFiles
47
47
  def new_runner(twine_file = nil)
48
48
  super(true, twine_file)
49
49
  end
50
50
 
51
51
  def test_creates_output_folder
52
52
  FileUtils.remove_entry_secure @output_dir
53
- new_runner.generate_all_string_files
53
+ new_runner.generate_all_localization_files
54
54
  assert File.exists? @output_dir
55
55
  end
56
56
 
57
57
  def test_creates_language_folders
58
- new_runner.generate_all_string_files
58
+ new_runner.generate_all_localization_files
59
59
  assert File.exists?(File.join(@output_dir, 'en.lproj')), "language folder 'en.lproj' should be created"
60
60
  assert File.exists?(File.join(@output_dir, 'es.lproj')), "language folder 'es.lproj' should be created"
61
61
  end
62
62
 
63
63
  def test_prints_empty_file_warnings
64
64
  empty_twine_file = build_twine_file('en') {}
65
- new_runner(empty_twine_file).generate_all_string_files
65
+ new_runner(empty_twine_file).generate_all_localization_files
66
66
 
67
67
  assert_match "Skipping file at path", Twine::stderr.string
68
68
  end
69
69
  end
70
70
 
71
- class TestValidate < CommandTestCase
71
+ class TestValidate < CommandTest
72
72
  def new_runner(validate)
73
73
  Dir.mkdir File.join @output_dir, 'values-en'
74
74
 
@@ -79,23 +79,23 @@ class TestGenerateAllStringFiles < CommandTestCase
79
79
 
80
80
  twine_file = build_twine_file 'en' do
81
81
  add_section 'Section' do
82
- add_row key: 'value'
83
- add_row key: 'value'
82
+ add_definition key: 'value'
83
+ add_definition key: 'value'
84
84
  end
85
85
  end
86
86
 
87
87
  Twine::Runner.new(options, twine_file)
88
88
  end
89
89
 
90
- def test_does_not_validate_strings_file
90
+ def test_does_not_validate_twine_file
91
91
  prepare_mock_formatter Twine::Formatters::Android
92
92
 
93
- new_runner(false).generate_all_string_files
93
+ new_runner(false).generate_all_localization_files
94
94
  end
95
95
 
96
- def test_validates_strings_file_if_validate
96
+ def test_validates_twine_file_if_validate
97
97
  assert_raises Twine::Error do
98
- new_runner(true).generate_all_string_files
98
+ new_runner(true).generate_all_localization_files
99
99
  end
100
100
  end
101
101
  end
@@ -1,6 +1,6 @@
1
- require 'command_test_case'
1
+ require 'command_test'
2
2
 
3
- class TestGenerateLocDrop < CommandTestCase
3
+ class TestGenerateLocalizationArchive < CommandTest
4
4
  def new_runner(twine_file = nil)
5
5
  options = {}
6
6
  options[:output_path] = @output_path
@@ -9,7 +9,7 @@ class TestGenerateLocDrop < CommandTestCase
9
9
  unless twine_file
10
10
  twine_file = build_twine_file 'en', 'fr' do
11
11
  add_section 'Section' do
12
- add_row key: 'value'
12
+ add_definition key: 'value'
13
13
  end
14
14
  end
15
15
  end
@@ -18,13 +18,13 @@ class TestGenerateLocDrop < CommandTestCase
18
18
  end
19
19
 
20
20
  def test_generates_zip_file
21
- new_runner.generate_loc_drop
21
+ new_runner.generate_localization_archive
22
22
 
23
23
  assert File.exists?(@output_path), "zip file should exist"
24
24
  end
25
25
 
26
26
  def test_zip_file_structure
27
- new_runner.generate_loc_drop
27
+ new_runner.generate_localization_archive
28
28
 
29
29
  names = []
30
30
  Zip::File.open(@output_path) do |zipfile|
@@ -39,16 +39,16 @@ class TestGenerateLocDrop < CommandTestCase
39
39
  formatter = prepare_mock_formatter Twine::Formatters::Apple
40
40
  formatter.expects(:format_file).twice
41
41
 
42
- new_runner.generate_loc_drop
42
+ new_runner.generate_localization_archive
43
43
  end
44
44
 
45
45
  def test_prints_empty_file_warnings
46
46
  empty_twine_file = build_twine_file('en') {}
47
- new_runner(empty_twine_file).generate_loc_drop
47
+ new_runner(empty_twine_file).generate_localization_archive
48
48
  assert_match "Skipping file", Twine::stderr.string
49
49
  end
50
50
 
51
- class TestValidate < CommandTestCase
51
+ class TestValidate < CommandTest
52
52
  def new_runner(validate)
53
53
  options = {}
54
54
  options[:output_path] = @output_path
@@ -57,23 +57,23 @@ class TestGenerateLocDrop < CommandTestCase
57
57
 
58
58
  twine_file = build_twine_file 'en' do
59
59
  add_section 'Section' do
60
- add_row key: 'value'
61
- add_row key: 'value'
60
+ add_definition key: 'value'
61
+ add_definition key: 'value'
62
62
  end
63
63
  end
64
64
 
65
65
  Twine::Runner.new(options, twine_file)
66
66
  end
67
67
 
68
- def test_does_not_validate_strings_file
68
+ def test_does_not_validate_twine_file
69
69
  prepare_mock_formatter Twine::Formatters::Android
70
70
 
71
- new_runner(false).generate_loc_drop
71
+ new_runner(false).generate_localization_archive
72
72
  end
73
73
 
74
- def test_validates_strings_file_if_validate
74
+ def test_validates_twine_file_if_validate
75
75
  assert_raises Twine::Error do
76
- new_runner(true).generate_loc_drop
76
+ new_runner(true).generate_localization_archive
77
77
  end
78
78
  end
79
79
  end
@@ -1,15 +1,15 @@
1
- require 'command_test_case'
1
+ require 'command_test'
2
2
 
3
- class TestGenerateStringFile < CommandTestCase
3
+ class TestGenerateLocalizationFile < CommandTest
4
4
  def new_runner(language, file)
5
5
  options = {}
6
6
  options[:output_path] = File.join(@output_dir, file) if file
7
7
  options[:languages] = language if language
8
8
 
9
- strings = Twine::StringsFile.new
10
- strings.language_codes.concat KNOWN_LANGUAGES
9
+ twine_file = Twine::TwineFile.new
10
+ twine_file.language_codes.concat KNOWN_LANGUAGES
11
11
 
12
- Twine::Runner.new(options, strings)
12
+ Twine::Runner.new(options, twine_file)
13
13
  end
14
14
 
15
15
  def prepare_mock_format_file_formatter(formatter_class)
@@ -20,25 +20,25 @@ class TestGenerateStringFile < CommandTestCase
20
20
  def test_deducts_android_format_from_output_path
21
21
  prepare_mock_format_file_formatter Twine::Formatters::Android
22
22
 
23
- new_runner('fr', 'fr.xml').generate_string_file
23
+ new_runner('fr', 'fr.xml').generate_localization_file
24
24
  end
25
25
 
26
26
  def test_deducts_apple_format_from_output_path
27
27
  prepare_mock_format_file_formatter Twine::Formatters::Apple
28
28
 
29
- new_runner('fr', 'fr.strings').generate_string_file
29
+ new_runner('fr', 'fr.strings').generate_localization_file
30
30
  end
31
31
 
32
32
  def test_deducts_jquery_format_from_output_path
33
33
  prepare_mock_format_file_formatter Twine::Formatters::JQuery
34
34
 
35
- new_runner('fr', 'fr.json').generate_string_file
35
+ new_runner('fr', 'fr.json').generate_localization_file
36
36
  end
37
37
 
38
38
  def test_deducts_gettext_format_from_output_path
39
39
  prepare_mock_format_file_formatter Twine::Formatters::Gettext
40
40
 
41
- new_runner('fr', 'fr.po').generate_string_file
41
+ new_runner('fr', 'fr.po').generate_localization_file
42
42
  end
43
43
 
44
44
  def test_deducts_language_from_output_path
@@ -46,7 +46,7 @@ class TestGenerateStringFile < CommandTestCase
46
46
  formatter = prepare_mock_formatter Twine::Formatters::Android
47
47
  formatter.expects(:format_file).with(random_language).returns(true)
48
48
 
49
- new_runner(nil, "#{random_language}.xml").generate_string_file
49
+ new_runner(nil, "#{random_language}.xml").generate_localization_file
50
50
  end
51
51
 
52
52
  def test_returns_error_if_nothing_written
@@ -54,11 +54,11 @@ class TestGenerateStringFile < CommandTestCase
54
54
  formatter.expects(:format_file).returns(false)
55
55
 
56
56
  assert_raises Twine::Error do
57
- new_runner('fr', 'fr.xml').generate_string_file
57
+ new_runner('fr', 'fr.xml').generate_localization_file
58
58
  end
59
59
  end
60
60
 
61
- class TestValidate < CommandTestCase
61
+ class TestValidate < CommandTest
62
62
  def new_runner(validate)
63
63
  options = {}
64
64
  options[:output_path] = @output_path
@@ -68,23 +68,23 @@ class TestGenerateStringFile < CommandTestCase
68
68
 
69
69
  twine_file = build_twine_file 'en' do
70
70
  add_section 'Section' do
71
- add_row key: 'value'
72
- add_row key: 'value'
71
+ add_definition key: 'value'
72
+ add_definition key: 'value'
73
73
  end
74
74
  end
75
75
 
76
76
  Twine::Runner.new(options, twine_file)
77
77
  end
78
78
 
79
- def test_does_not_validate_strings_file
79
+ def test_does_not_validate_twine_file
80
80
  prepare_mock_formatter Twine::Formatters::Android
81
81
 
82
- new_runner(false).generate_string_file
82
+ new_runner(false).generate_localization_file
83
83
  end
84
84
 
85
- def test_validates_strings_file_if_validate
85
+ def test_validates_twine_file_if_validate
86
86
  assert_raises Twine::Error do
87
- new_runner(true).generate_string_file
87
+ new_runner(true).generate_localization_file
88
88
  end
89
89
  end
90
90
  end
@@ -1,84 +1,84 @@
1
- require 'twine_test_case'
1
+ require 'twine_test'
2
2
 
3
- class TestOutputProcessor < TwineTestCase
3
+ class TestOutputProcessor < TwineTest
4
4
  def setup
5
5
  super
6
6
 
7
- @strings = build_twine_file 'en', 'fr' do
7
+ @twine_file = build_twine_file 'en', 'fr' do
8
8
  add_section 'Section' do
9
- add_row key1: 'value1', tags: ['tag1']
10
- add_row key2: 'value2', tags: ['tag1', 'tag2']
11
- add_row key3: 'value3', tags: ['tag2']
12
- add_row key4: { en: 'value4-en', fr: 'value4-fr' }
9
+ add_definition key1: 'value1', tags: ['tag1']
10
+ add_definition key2: 'value2', tags: ['tag1', 'tag2']
11
+ add_definition key3: 'value3', tags: ['tag2']
12
+ add_definition key4: { en: 'value4-en', fr: 'value4-fr' }
13
13
  end
14
14
  end
15
15
  end
16
16
 
17
17
  def test_includes_all_keys_by_default
18
- processor = Twine::Processors::OutputProcessor.new(@strings, {})
18
+ processor = Twine::Processors::OutputProcessor.new(@twine_file, {})
19
19
  result = processor.process('en')
20
20
 
21
- assert_equal %w(key1 key2 key3 key4), result.strings_map.keys.sort
21
+ assert_equal %w(key1 key2 key3 key4), result.definitions_by_key.keys.sort
22
22
  end
23
23
 
24
24
  def test_filter_by_tag
25
- processor = Twine::Processors::OutputProcessor.new(@strings, { tags: ['tag1'] })
25
+ processor = Twine::Processors::OutputProcessor.new(@twine_file, { tags: [['tag1']] })
26
26
  result = processor.process('en')
27
27
 
28
- assert_equal %w(key1 key2), result.strings_map.keys.sort
28
+ assert_equal %w(key1 key2), result.definitions_by_key.keys.sort
29
29
  end
30
30
 
31
31
  def test_filter_by_multiple_tags
32
- processor = Twine::Processors::OutputProcessor.new(@strings, { tags: ['tag1', 'tag2'] })
32
+ processor = Twine::Processors::OutputProcessor.new(@twine_file, { tags: [['tag1', 'tag2']] })
33
33
  result = processor.process('en')
34
34
 
35
- assert_equal %w(key1 key2 key3), result.strings_map.keys.sort
35
+ assert_equal %w(key1 key2 key3), result.definitions_by_key.keys.sort
36
36
  end
37
37
 
38
38
  def test_filter_untagged
39
- processor = Twine::Processors::OutputProcessor.new(@strings, { tags: ['tag1'], untagged: true })
39
+ processor = Twine::Processors::OutputProcessor.new(@twine_file, { tags: [['tag1']], untagged: true })
40
40
  result = processor.process('en')
41
41
 
42
- assert_equal %w(key1 key2 key4), result.strings_map.keys.sort
42
+ assert_equal %w(key1 key2 key4), result.definitions_by_key.keys.sort
43
43
  end
44
44
 
45
45
  def test_include_translated
46
- processor = Twine::Processors::OutputProcessor.new(@strings, { include: :translated })
46
+ processor = Twine::Processors::OutputProcessor.new(@twine_file, { include: :translated })
47
47
  result = processor.process('fr')
48
48
 
49
- assert_equal %w(key4), result.strings_map.keys.sort
49
+ assert_equal %w(key4), result.definitions_by_key.keys.sort
50
50
  end
51
51
 
52
52
  def test_include_untranslated
53
- processor = Twine::Processors::OutputProcessor.new(@strings, { include: :untranslated })
53
+ processor = Twine::Processors::OutputProcessor.new(@twine_file, { include: :untranslated })
54
54
  result = processor.process('fr')
55
55
 
56
- assert_equal %w(key1 key2 key3), result.strings_map.keys.sort
56
+ assert_equal %w(key1 key2 key3), result.definitions_by_key.keys.sort
57
57
  end
58
58
 
59
- class TranslationFallback < TwineTestCase
59
+ class TranslationFallback < TwineTest
60
60
  def setup
61
61
  super
62
62
 
63
- @strings = build_twine_file 'en', 'fr', 'de' do
63
+ @twine_file = build_twine_file 'en', 'fr', 'de' do
64
64
  add_section 'Section' do
65
- add_row key1: { en: 'value1-en', fr: 'value1-fr' }
65
+ add_definition key1: { en: 'value1-en', fr: 'value1-fr' }
66
66
  end
67
67
  end
68
68
  end
69
69
 
70
70
  def test_fallback_to_default_language
71
- processor = Twine::Processors::OutputProcessor.new(@strings, {})
71
+ processor = Twine::Processors::OutputProcessor.new(@twine_file, {})
72
72
  result = processor.process('de')
73
73
 
74
- assert_equal 'value1-en', result.strings_map['key1'].translations['de']
74
+ assert_equal 'value1-en', result.definitions_by_key['key1'].translations['de']
75
75
  end
76
76
 
77
77
  def test_fallback_to_developer_language
78
- processor = Twine::Processors::OutputProcessor.new(@strings, {developer_language: 'fr'})
78
+ processor = Twine::Processors::OutputProcessor.new(@twine_file, {developer_language: 'fr'})
79
79
  result = processor.process('de')
80
80
 
81
- assert_equal 'value1-fr', result.strings_map['key1'].translations['de']
81
+ assert_equal 'value1-fr', result.definitions_by_key['key1'].translations['de']
82
82
  end
83
83
  end
84
84
 
@@ -1,6 +1,6 @@
1
- require 'twine_test_case'
1
+ require 'twine_test'
2
2
 
3
- class PlaceholderTestCase < TwineTestCase
3
+ class PlaceholderTest < TwineTest
4
4
  def assert_starts_with(prefix, value)
5
5
  msg = message(nil) { "Expected #{mu_pp(value)} to start with #{mu_pp(prefix)}" }
6
6
  assert value.start_with?(prefix), msg
@@ -11,23 +11,25 @@ class PlaceholderTestCase < TwineTestCase
11
11
  lucky = lambda { rand > 0.5 }
12
12
  placeholder = '%'
13
13
  placeholder += (rand * 20).to_i.to_s + '$' if lucky.call
14
- placeholder += '-+ 0#'.chars.to_a.sample if lucky.call
14
+ placeholder += '-+0#'.chars.to_a.sample if lucky.call
15
15
  placeholder += (0.upto(20).map(&:to_s) << "*").sample if lucky.call
16
16
  placeholder += '.' + (0.upto(20).map(&:to_s) << "*").sample if lucky.call
17
17
  placeholder += %w(h hh l ll L z j t).sample if lucky.call
18
18
  placeholder += type || 'diufFeEgGxXocpaA'.chars.to_a.sample # this does not contain s or @ because strings are a special case
19
19
  end
20
- end
21
20
 
22
- class PlaceholderTest < TwineTestCase
23
- class ToAndroid < PlaceholderTestCase
21
+ class ToAndroid < PlaceholderTest
24
22
  def to_android(value)
25
23
  Twine::Placeholders.convert_placeholders_from_twine_to_android(value)
26
24
  end
27
25
 
28
- def test_replaces_string_placeholder
26
+ def test_replaces_simple_string_placeholder
27
+ assert_equal "some '%s' value", to_android("some '%@' value")
28
+ end
29
+
30
+ def test_replaces_complicated_string_placeholder
29
31
  placeholder = placeholder('@')
30
- expected = placeholder
32
+ expected = placeholder.dup
31
33
  expected[-1] = 's'
32
34
  assert_equal "some #{expected} value", to_android("some #{placeholder} value")
33
35
  end
@@ -41,6 +43,11 @@ class PlaceholderTest < TwineTestCase
41
43
  assert_equal "some % value", to_android("some % value")
42
44
  end
43
45
 
46
+ def test_does_not_modify_single_percent_signs_when_followed_by_space_and_format_letter
47
+ # Said differently: formartter parser should not recognize %a in "70% and"
48
+ assert_equal 'If 70% and 30% dog 80% end', to_android('If 70% and 30% dog 80% end')
49
+ end
50
+
44
51
  def test_escapes_single_percent_signs_if_placeholder_present
45
52
  assert_starts_with "some %% v", to_android("some % value #{placeholder}")
46
53
  end
@@ -74,7 +81,7 @@ class PlaceholderTest < TwineTestCase
74
81
  end
75
82
  end
76
83
 
77
- class FromAndroid < PlaceholderTestCase
84
+ class FromAndroid < PlaceholderTest
78
85
  def from_android(value)
79
86
  Twine::Placeholders.convert_placeholders_from_android_to_twine(value)
80
87
  end
@@ -83,4 +90,32 @@ class PlaceholderTest < TwineTestCase
83
90
  assert_equal "some %@ value", from_android("some %s value")
84
91
  end
85
92
  end
93
+
94
+ class ToFlash < PlaceholderTest
95
+ def to_flash(value)
96
+ Twine::Placeholders.convert_placeholders_from_twine_to_flash(value)
97
+ end
98
+
99
+ def test_replaces_placeholder
100
+ assert_equal "some {0} text", to_flash("some #{placeholder} text")
101
+ end
102
+
103
+ def test_replaces_string_placeholder
104
+ assert_equal "some {0} text", to_flash("some #{placeholder('@')} text")
105
+ end
106
+
107
+ def test_numbers_placeholders
108
+ assert_equal "some {0} more {1} text {2}", to_flash("some #{placeholder('@')} more #{placeholder('@')} text #{placeholder('@')}")
109
+ end
110
+ end
111
+
112
+ class FromFlash < PlaceholderTest
113
+ def from_flash(value)
114
+ Twine::Placeholders.convert_placeholders_from_flash_to_twine(value)
115
+ end
116
+
117
+ def test_maps_all_placeholders_to_string
118
+ assert_equal "some %@ more %@ text %@", from_flash("some {0} more {1} text {2}")
119
+ end
120
+ end
86
121
  end