any2tmx 1.0.4 → 1.1.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
  SHA1:
3
- metadata.gz: 4d90cd3e9e2eaec60045ed8bbebb270b875df53c
4
- data.tar.gz: ac99873e75d2594df5eece8e67cdd6eaa1588b9f
3
+ metadata.gz: dfbf800c45d800fa53efa6f1f142f154e6ea2be6
4
+ data.tar.gz: 19c4b39b0252af8fb49cbeb4fc994c14f5c79571
5
5
  SHA512:
6
- metadata.gz: 0fdc99691eca01b66e6f9ec78796befa10f7aa580a7a194c2c12e98a017df77217970e6993d7c2b0ab4d4024062d3945d5bf82d57290ebfede7d059cb2656e2d
7
- data.tar.gz: 091ca3fe3de6376ceea1ca6f5a1af4726e663dd5745e8fed261d67a0863a39dd5f4cecb1ffc0bae23a7264e2a5424168e586098dfaa1fb726a2b4debcaca98a2
6
+ metadata.gz: e2a67b0fce2c98fe75e198f12822df3567138a4a11f2abae9b8255836c0a724a719912fa3db011b0b6c26f9036ddeee7e197fbb1cd87b564009dfcb5b0e29820
7
+ data.tar.gz: 19e26011be1125aa387c05b6cc7ae388ef1ff04766bee422f9341e8fd630d602a635f03067ca10f8545a34cbb61a281ef94d9d4a5275a5ca304e3153c4b76804
@@ -1,24 +1,27 @@
1
- == 1.0.0
1
+ == 1.1.0
2
2
 
3
- * Birthday!
3
+ * Depend on Abroad for parsing, which removes a lot of code.
4
+ * General cleanup and refactoring.
5
+ * Added ability to specify more than one target file.
4
6
 
5
- == 1.0.0
7
+ == 1.0.4
6
8
 
7
- * Renamed gem from yaml2tmx to any2tmx.
8
- * Added support for JSON and Android XML.
9
+ * Fixing bug with JSON processor causing crash.
9
10
 
10
- == 1.0.1
11
+ == 1.0.3
11
12
 
12
- * Add ability to load files by name or by contents.
13
+ * Stringify keys when processing YAML
13
14
 
14
15
  == 1.0.2
15
16
 
16
17
  * Fix Android transform bug
17
18
 
18
- == 1.0.3
19
+ == 1.0.1
19
20
 
20
- * Stringify keys when processing YAML
21
+ * Add ability to load files by name or by contents.
21
22
 
22
- == 1.0.4
23
+ == 1.0.0
23
24
 
24
- * Fixing bug with JSON processor causing crash.
25
+ * Birthday!
26
+ * Renamed gem from yaml2tmx to any2tmx.
27
+ * Added support for JSON and Android XML.
@@ -2,25 +2,25 @@ $:.unshift File.join(File.dirname(__FILE__), 'lib')
2
2
  require 'any2tmx/version'
3
3
 
4
4
  Gem::Specification.new do |s|
5
- s.name = "any2tmx"
5
+ s.name = 'any2tmx'
6
6
  s.version = ::Any2Tmx::VERSION
7
- s.authors = ["Cameron Dutro"]
8
- s.email = ["camertron@gmail.com"]
9
- s.homepage = "http://github.com/camertron/any2tmx"
7
+ s.authors = ['Cameron Dutro']
8
+ s.email = ['camertron@gmail.com']
9
+ s.homepage = 'http://github.com/camertron/any2tmx'
10
10
 
11
- s.description = s.summary = "A command-line tool to convert certain file types to the standard TMX format for translation memories."
11
+ s.description = s.summary = 'A command-line tool to convert certain file types to the standard TMX format for translation memories.'
12
12
 
13
13
  s.platform = Gem::Platform::RUBY
14
14
  s.has_rdoc = true
15
15
 
16
- s.add_dependency 'xml-write-stream', '~> 1.0'
16
+ s.add_dependency 'abroad', '~> 4.0'
17
17
  s.add_dependency 'nokogiri', '~> 1.6'
18
- s.add_dependency 'htmlentities', '~> 4.3'
18
+ s.add_dependency 'xml-write-stream', '~> 1.0'
19
19
 
20
- s.executables << 'yaml2tmx'
21
- s.executables << 'json2tmx'
22
20
  s.executables << 'android2tmx'
21
+ s.executables << 'json2tmx'
22
+ s.executables << 'yaml2tmx'
23
23
 
24
24
  s.require_path = 'lib'
25
- s.files = Dir["{lib,spec}/**/*", "Gemfile", "History.txt", "README.md", "Rakefile", "any2tmx.gemspec"]
25
+ s.files = Dir["{lib,spec}/**/*", 'Gemfile', 'History.txt', 'README.md', 'Rakefile', 'any2tmx.gemspec']
26
26
  end
@@ -14,10 +14,8 @@ if options.help?
14
14
  exit 0
15
15
  end
16
16
 
17
- transform = Any2Tmx::Transforms::AndroidTransform.new(options)
18
- result = transform.result
19
-
20
- STDERR.write("Matched #{result.processed_count} of #{result.source_phrase_count} source phrases\n")
17
+ transform = Any2Tmx::Transformer.new(options)
18
+ result = transformer.transform
21
19
 
22
20
  stream = if options.output
23
21
  File.open(options.output, 'w+')
@@ -25,7 +23,7 @@ else
25
23
  STDOUT
26
24
  end
27
25
 
28
- result.write(stream)
26
+ Any2Tmx::TmxWriter.write(result, options, stream)
29
27
 
30
28
  if options.output
31
29
  STDERR.write("Wrote #{options.output}\n")
@@ -14,10 +14,8 @@ if options.help?
14
14
  exit 0
15
15
  end
16
16
 
17
- transform = Any2Tmx::Transforms::JsonTransform.new(options)
18
- result = transform.result
19
-
20
- STDERR.write("Matched #{result.processed_count} of #{result.source_phrase_count} source phrases\n")
17
+ transform = Any2Tmx::Transformer.new(options)
18
+ result = transformer.transform
21
19
 
22
20
  stream = if options.output
23
21
  File.open(options.output, 'w+')
@@ -25,7 +23,7 @@ else
25
23
  STDOUT
26
24
  end
27
25
 
28
- result.write(stream)
26
+ Any2Tmx::TmxWriter.write(result, options, stream)
29
27
 
30
28
  if options.output
31
29
  STDERR.write("Wrote #{options.output}\n")
@@ -14,10 +14,8 @@ if options.help?
14
14
  exit 0
15
15
  end
16
16
 
17
- transform = Any2Tmx::Transforms::YamlTransform.new(options)
18
- result = transform.result
19
-
20
- STDERR.write("Matched #{result.processed_count} of #{result.source_phrase_count} source phrases\n")
17
+ transformer = Any2Tmx::Transformer.new(options)
18
+ result = transformer.transform
21
19
 
22
20
  stream = if options.output
23
21
  File.open(options.output, 'w+')
@@ -25,7 +23,7 @@ else
25
23
  STDOUT
26
24
  end
27
25
 
28
- result.write(stream)
26
+ Any2Tmx::TmxWriter.write(result, options, stream)
29
27
 
30
28
  if options.output
31
29
  STDERR.write("Wrote #{options.output}\n")
@@ -1,8 +1,5 @@
1
1
  module Any2Tmx
2
- autoload :AndroidXmlParser, 'any2tmx/android_xml_parser'
3
- autoload :Options, 'any2tmx/options'
4
- autoload :PhraseSet, 'any2tmx/phrase_set'
5
- autoload :TmxWriter, 'any2tmx/tmx_writer'
6
- autoload :Transforms, 'any2tmx/transforms'
7
- autoload :Traversable, 'any2tmx/traversable'
2
+ autoload :Options, 'any2tmx/options'
3
+ autoload :TmxWriter, 'any2tmx/tmx_writer'
4
+ autoload :Transformer, 'any2tmx/transformer'
8
5
  end
@@ -5,7 +5,7 @@ module Any2Tmx
5
5
  attr_reader :errors
6
6
 
7
7
  def initialize(executable_name)
8
- @options = {}
8
+ @options = { targets: [] }
9
9
  @errors = []
10
10
 
11
11
  OptionParser.new do |opts|
@@ -13,14 +13,12 @@ module Any2Tmx
13
13
 
14
14
  opts.on('-s', '--source [file]:[locale]', 'File containing phrases in the source locale (locale appended with colon).') do |source|
15
15
  file, locale = source.split(':')
16
- @options[:source] = file
17
- @options[:source_locale] = locale
16
+ @options[:source] = { file: file, locale: locale }
18
17
  end
19
18
 
20
19
  opts.on('-t', '--target [file]:[locale]', 'File containing translations in the target locale (locale appended with colon).') do |target|
21
20
  file, locale = target.split(':')
22
- @options[:target] = file
23
- @options[:target_locale] = locale
21
+ @options[:targets] << { file: file, locale: locale }
24
22
  end
25
23
 
26
24
  opts.on('-o', '--output [file]', 'The TMX output file to write. If not specified, output is printed to stdout.') do |output|
@@ -48,16 +46,8 @@ module Any2Tmx
48
46
  @options[:source]
49
47
  end
50
48
 
51
- def target
52
- @options[:target]
53
- end
54
-
55
- def source_locale
56
- @options[:source_locale]
57
- end
58
-
59
- def target_locale
60
- @options[:target_locale]
49
+ def targets
50
+ @options[:targets]
61
51
  end
62
52
 
63
53
  def output
@@ -85,34 +75,36 @@ module Any2Tmx
85
75
  unless help?
86
76
  before_validate
87
77
  validate_source
88
- validate_target
78
+ validate_targets
89
79
  validate_output
90
80
  after_validate
91
81
  end
92
82
  end
93
83
 
94
84
  def validate_source
95
- unless File.exist?(source)
85
+ unless File.exist?(source[:file])
96
86
  errors << 'Source file does not exist.'
97
87
  end
98
88
 
99
- unless source_locale
89
+ unless source[:locale]
100
90
  errors << 'Source locale not provided. Try running with the -h option for usage details.'
101
91
  end
102
92
  end
103
93
 
104
- def validate_target
105
- unless File.exist?(target)
106
- errors << 'Target file does not exist.'
107
- end
94
+ def validate_targets
95
+ targets.each do |target|
96
+ unless File.exist?(target[:file])
97
+ errors << 'Target file does not exist.'
98
+ end
108
99
 
109
- unless target_locale
110
- errors << 'Target locale not provided. Try running with the -h option for usage details.'
100
+ unless target[:locale]
101
+ errors << 'Target locale not provided. Try running with the -h option for usage details.'
102
+ end
111
103
  end
112
104
  end
113
105
 
114
106
  def validate_output
115
- unless File.exist?(File.dirname(target))
107
+ if output && !File.exist?(File.dirname(output))
116
108
  errors << 'Output path does not exist.'
117
109
  end
118
110
  end
@@ -3,27 +3,25 @@ require 'xml-write-stream'
3
3
  module Any2Tmx
4
4
  class TmxWriter
5
5
  class << self
6
- def write(trans_map, source_locale, target_locale, io)
6
+ def write(trans_map, options, io)
7
7
  writer = XmlWriteStream.from_stream(io)
8
8
  writer.open_tag('tmx', version: '1.4')
9
- writer.open_single_line_tag('header', srclang: source_locale, datatype: 'plaintext', segtype: 'paragraph')
9
+ writer.open_single_line_tag('header', srclang: options.source[:locale], datatype: 'plaintext', segtype: 'paragraph')
10
10
  writer.close_tag
11
11
 
12
12
  writer.open_tag('body')
13
13
 
14
- trans_map.each_pair do |source_phrase, target_phrase|
14
+ trans_map.each_pair do |_, target_translations|
15
15
  writer.open_tag('tu')
16
- writer.open_tag('tuv', 'xml:lang' => source_locale)
17
- writer.open_single_line_tag('seg')
18
- writer.write_text(source_phrase)
19
- writer.close_tag # seg
20
- writer.close_tag # tuv
21
16
 
22
- writer.open_tag('tuv', 'xml:lang' => target_locale)
23
- writer.open_single_line_tag('seg')
24
- writer.write_text(target_phrase)
25
- writer.close_tag # seg
26
- writer.close_tag # tuv
17
+ target_translations.each do |locale, translation|
18
+ writer.open_tag('tuv', 'xml:lang' => locale)
19
+ writer.open_single_line_tag('seg')
20
+ writer.write_text(translation)
21
+ writer.close_tag # seg
22
+ writer.close_tag # tuv
23
+ end
24
+
27
25
  writer.close_tag # tu
28
26
  end
29
27
 
@@ -0,0 +1,60 @@
1
+ require 'abroad'
2
+
3
+ module Any2Tmx
4
+ class Transformer
5
+ EXTRACTOR_EXTENSIONS = {
6
+ '.yml' => 'yaml/rails',
7
+ '.json' => 'json/key-value',
8
+ '.xml' => 'android/xml'
9
+ }
10
+
11
+ attr_reader :options
12
+
13
+ def initialize(options)
14
+ @options = options
15
+ end
16
+
17
+ def transform
18
+ source_phrases = extract_from(options.source[:file])
19
+ result = source_phrases.each_with_object({}) do |(k, v), result|
20
+ result[k] = { options.source[:locale] => v.to_s }
21
+ end
22
+
23
+ options.targets.each do |target|
24
+ target_phrases = extract_from(target[:file])
25
+
26
+ source_phrases.each_pair do |source_key, _|
27
+ translation = target_phrases[source_key]
28
+
29
+ if !translation.nil?
30
+ result[source_key][target[:locale]] = translation.to_s
31
+ end
32
+ end
33
+ end
34
+
35
+ result
36
+ end
37
+
38
+ private
39
+
40
+ def extract_from(file)
41
+ {}.tap do |phrases|
42
+ extractor.open(file) do |extractor|
43
+ extractor.extract_each { |k, v| phrases[k] = v }
44
+ end
45
+ end
46
+ end
47
+
48
+ def extractor
49
+ @extractor ||= Abroad.extractor(extractor_id)
50
+ end
51
+
52
+ def extractor_id
53
+ EXTRACTOR_EXTENSIONS[source_extension]
54
+ end
55
+
56
+ def source_extension
57
+ File.extname(options.source[:file])
58
+ end
59
+ end
60
+ end
@@ -1,3 +1,3 @@
1
1
  module Any2Tmx
2
- VERSION = '1.0.4'
2
+ VERSION = '1.1.0'
3
3
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: any2tmx
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cameron Dutro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-18 00:00:00.000000000 Z
11
+ date: 2016-11-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: xml-write-stream
14
+ name: abroad
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '4.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: '4.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: nokogiri
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -39,27 +39,27 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.6'
41
41
  - !ruby/object:Gem::Dependency
42
- name: htmlentities
42
+ name: xml-write-stream
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '4.3'
47
+ version: '1.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '4.3'
54
+ version: '1.0'
55
55
  description: A command-line tool to convert certain file types to the standard TMX
56
56
  format for translation memories.
57
57
  email:
58
58
  - camertron@gmail.com
59
59
  executables:
60
- - yaml2tmx
61
- - json2tmx
62
60
  - android2tmx
61
+ - json2tmx
62
+ - yaml2tmx
63
63
  extensions: []
64
64
  extra_rdoc_files: []
65
65
  files:
@@ -71,17 +71,9 @@ files:
71
71
  - bin/json2tmx
72
72
  - bin/yaml2tmx
73
73
  - lib/any2tmx.rb
74
- - lib/any2tmx/android_xml_parser.rb
75
74
  - lib/any2tmx/options.rb
76
- - lib/any2tmx/phrase_set.rb
77
75
  - lib/any2tmx/tmx_writer.rb
78
- - lib/any2tmx/transforms.rb
79
- - lib/any2tmx/transforms/android_transform.rb
80
- - lib/any2tmx/transforms/json_transform.rb
81
- - lib/any2tmx/transforms/result.rb
82
- - lib/any2tmx/transforms/transform.rb
83
- - lib/any2tmx/transforms/yaml_transform.rb
84
- - lib/any2tmx/traversable.rb
76
+ - lib/any2tmx/transformer.rb
85
77
  - lib/any2tmx/version.rb
86
78
  homepage: http://github.com/camertron/any2tmx
87
79
  licenses: []
@@ -108,4 +100,3 @@ specification_version: 4
108
100
  summary: A command-line tool to convert certain file types to the standard TMX format
109
101
  for translation memories.
110
102
  test_files: []
111
- has_rdoc: true
@@ -1,146 +0,0 @@
1
- require 'nokogiri'
2
- require 'htmlentities'
3
-
4
- # These classes have been adapted from:
5
- # https://github.com/rosette-proj/rosette-extractor-xml
6
-
7
- class HTMLEntities
8
- MAPPINGS['android_xml'] = MAPPINGS['xhtml1'].dup.tap do |mappings|
9
- mappings.delete('apos')
10
- end
11
-
12
- FLAVORS << 'android_xml'
13
-
14
- class AndroidXmlDecoder < Decoder
15
- def initialize
16
- super('android_xml')
17
- end
18
- end
19
- end
20
-
21
- module Any2Tmx
22
- class AndroidXmlParser
23
- class << self
24
- def parse(xml_content)
25
- doc = parse_xml(xml_content)
26
- result = {}.tap do |result|
27
- collector = lambda { |text, key| result[key] = text }
28
- each_string_entry(doc, &collector)
29
- each_array_entry(doc, &collector)
30
- each_plural_entry(doc, &collector)
31
- end
32
- end
33
-
34
- protected
35
-
36
- def parse_xml(xml_content)
37
- Nokogiri::XML(xml_content) do |config|
38
- config.options = Nokogiri::XML::ParseOptions::NONET
39
- end
40
- end
41
-
42
- def each_string_entry(doc)
43
- doc.xpath('//string').each do |node|
44
- yield(
45
- text_from(node),
46
- name_from(node)
47
- )
48
- end
49
- end
50
-
51
- def each_array_entry(doc)
52
- doc.xpath('//string-array').each do |array|
53
- prefix = name_from(array)
54
-
55
- array.xpath('item').each_with_index do |item, idx|
56
- yield(
57
- text_from(item),
58
- "#{prefix}.#{idx}"
59
- )
60
- end
61
- end
62
- end
63
-
64
- def each_plural_entry(doc)
65
- doc.xpath('//plurals').each do |plurals|
66
- prefix = name_from(plurals)
67
-
68
- plurals.xpath('item').each do |item|
69
- quantity = item.attributes['quantity'].value
70
-
71
- yield(
72
- text_from(item),
73
- "#{prefix}.#{quantity}"
74
- )
75
- end
76
- end
77
- end
78
-
79
- def text_from(node)
80
- builder = Nokogiri::XML::Builder.new do |builder|
81
- builder.root do
82
- node.children.each do |child|
83
- serialize(child, builder)
84
- end
85
- end
86
- end
87
-
88
- # safe to call `strip` after `to_xml` because any string that
89
- # needs leading or trailing whitespace preserved should be wrapped
90
- # in double quotes
91
- unescape(
92
- strip_enclosing_quotes(
93
- builder.doc.xpath('/root/node()').to_xml.strip
94
- )
95
- )
96
- end
97
-
98
- def serialize(node, builder)
99
- if node.text?
100
- builder.text(unescape(node.text))
101
- else
102
- builder.send("#{node.name}_", node.attributes) do
103
- node.children.each do |child|
104
- serialize(child, builder)
105
- end
106
- end
107
- end
108
- end
109
-
110
- def name_from(node)
111
- if attribute = node.attributes['name']
112
- attribute.value
113
- end
114
- end
115
-
116
- def unescape(text)
117
- text = text
118
- .gsub("\\'", "'")
119
- .gsub('\\"', '"')
120
- .gsub("\\n", "\n")
121
- .gsub("\\r", "\r")
122
- .gsub("\\t", "\t")
123
-
124
- coder.decode(text)
125
- end
126
-
127
- def coder
128
- @coder ||= HTMLEntities::AndroidXmlDecoder.new
129
- end
130
-
131
- def strip_enclosing_quotes(text)
132
- quote = case text[0]
133
- when "'", '"'
134
- text[0]
135
- end
136
-
137
- if quote
138
- text.gsub(/\A#{quote}(.*)#{quote}\z/) { $1 }
139
- else
140
- text
141
- end
142
- end
143
-
144
- end
145
- end
146
- end
@@ -1,14 +0,0 @@
1
- module Any2Tmx
2
- class PhraseSet
3
- attr_reader :traversable, :locale
4
-
5
- def initialize(traversable, locale)
6
- @traversable = traversable
7
- @locale = locale
8
- end
9
-
10
- def zip(other_set, &block)
11
- traversable.zip(other_set.traversable, &block)
12
- end
13
- end
14
- end
@@ -1,9 +0,0 @@
1
- module Any2Tmx
2
- module Transforms
3
- autoload :AndroidTransform, 'any2tmx/transforms/android_transform'
4
- autoload :JsonTransform, 'any2tmx/transforms/json_transform'
5
- autoload :Transform, 'any2tmx/transforms/transform'
6
- autoload :Result, 'any2tmx/transforms/result'
7
- autoload :YamlTransform, 'any2tmx/transforms/yaml_transform'
8
- end
9
- end
@@ -1,18 +0,0 @@
1
- module Any2Tmx
2
- module Transforms
3
- class AndroidTransform < Transform
4
- private
5
-
6
- def load_file(file, locale)
7
- phrases = File.read(file)
8
- load(phrases, locale)
9
- end
10
-
11
- def load(contents, locale)
12
- contents = Any2Tmx::AndroidXmlParser.parse(contents)
13
- traversable = Any2Tmx::Traversable.new(contents)
14
- Any2Tmx::PhraseSet.new(traversable, locale)
15
- end
16
- end
17
- end
18
- end
@@ -1,19 +0,0 @@
1
- require 'json'
2
-
3
- module Any2Tmx
4
- module Transforms
5
- class JsonTransform < Transform
6
- private
7
-
8
- def load_file(file, locale)
9
- phrases = File.read(file)
10
- load(phrases, locale)
11
- end
12
-
13
- def load(contents, locale)
14
- traversable = Any2Tmx::Traversable.new(JSON.parse(contents))
15
- Any2Tmx::PhraseSet.new(traversable, locale)
16
- end
17
- end
18
- end
19
- end
@@ -1,24 +0,0 @@
1
- module Any2Tmx
2
- module Transforms
3
- class Result
4
- attr_reader :source, :target, :collection, :processed_count
5
-
6
- def initialize(source, target, collection, processed_count)
7
- @source = source
8
- @target = target
9
- @collection = collection
10
- @processed_count = processed_count
11
- end
12
-
13
- def source_phrase_count
14
- source.traversable.size
15
- end
16
-
17
- def write(io)
18
- Any2Tmx::TmxWriter.write(
19
- collection, source.locale, target.locale, io
20
- )
21
- end
22
- end
23
- end
24
- end
@@ -1,39 +0,0 @@
1
- module Any2Tmx
2
- module Transforms
3
- class Transform
4
- attr_reader :options
5
-
6
- def initialize(options)
7
- @options = options
8
- end
9
-
10
- def result
11
- source = read(options.source, options.source_locale)
12
- target = read(options.target, options.target_locale)
13
- count = 0
14
- zipped = source.zip(target) { count += 1 }
15
- Result.new(source, target, zipped, count)
16
- end
17
-
18
- private
19
-
20
- def read(location_or_contents, locale)
21
- if File.exist?(location_or_contents)
22
- load_file(location_or_contents, locale)
23
- else
24
- load(location_or_contents, locale)
25
- end
26
- end
27
-
28
- def load_file(file, locale)
29
- raise NotImplementedError,
30
- "#{__method__} must be defined in derived classes"
31
- end
32
-
33
- def load(file, locale)
34
- raise NotImplementedError,
35
- "#{__method__} must be defined in derived classes"
36
- end
37
- end
38
- end
39
- end
@@ -1,25 +0,0 @@
1
- require 'yaml'
2
-
3
- module Any2Tmx
4
- module Transforms
5
- class YamlTransform < Transform
6
- private
7
-
8
- def load_file(file, locale)
9
- phrases = File.read(file)
10
- load(phrases, locale)
11
- end
12
-
13
- def load(contents, locale)
14
- contents = YAML.load(contents)
15
-
16
- if contents.include?(locale)
17
- contents = contents[locale]
18
- end
19
-
20
- traversable = Any2Tmx::Traversable.new(contents).stringify_keys
21
- Any2Tmx::PhraseSet.new(traversable, locale)
22
- end
23
- end
24
- end
25
- end
@@ -1,127 +0,0 @@
1
- module Any2Tmx
2
- class Traversable
3
- attr_reader :collection
4
-
5
- def initialize(collection)
6
- @collection = collection
7
- end
8
-
9
- def each_entry(&block)
10
- if block_given?
11
- each_entry_helper(collection, [], nil) do |entry, path, last_key|
12
- yield entry, path + [last_key]
13
- end
14
- else
15
- to_enum(__method__)
16
- end
17
- end
18
-
19
- def size
20
- each_entry.inject(0) { |ret, _| ret + 1 }
21
- end
22
-
23
- def dig_each(path)
24
- if block_given?
25
- path.inject(:start) do |ret, seg|
26
- if ret == :start
27
- yield collection, seg
28
- collection[seg]
29
- elsif ret
30
- if seg.is_a?(Numeric) && ret.is_a?(Array)
31
- yield ret, seg
32
- ret[seg] # array index case
33
- elsif ret.is_a?(Hash)
34
- yield ret, seg
35
- ret[seg] # hash key case
36
- end
37
- end
38
- end
39
- else
40
- to_enum(__method__, path)
41
- end
42
- end
43
-
44
- def dig(path)
45
- return collection if path.empty?
46
- dig_each(path) {}
47
- end
48
-
49
- def transform
50
- if block_given?
51
- self.class.new(make_empty(sym_from(collection))).tap do |copy|
52
- each_entry_helper(collection, [], nil) do |entry, path, last_key|
53
- dig_each(path).inject(copy.collection) do |copy_obj, (obj, key)|
54
- copy_obj[key] ||= make_empty(sym_from(obj[key]))
55
- copy_obj[key]
56
- end
57
-
58
- yield copy.dig(path), last_key, entry
59
- end
60
- end
61
- else
62
- to_enum(__method__)
63
- end
64
- end
65
-
66
- def zip(other_traversable)
67
- each_entry.each_with_object({}) do |(entry, path), ret|
68
- other_entry = other_traversable.dig(path)
69
- ret[entry] = other_entry if other_entry
70
- yield if block_given? && other_entry
71
- end
72
- end
73
-
74
- def stringify_keys
75
- transform do |obj, key, value|
76
- obj[stringify(key)] = value
77
- end
78
- end
79
-
80
- private
81
-
82
- def stringify(obj)
83
- obj.is_a?(Symbol) ? obj.to_s : obj
84
- end
85
-
86
- def sym_from(obj)
87
- case obj
88
- when Hash
89
- :hash
90
- when Array
91
- :array
92
- end
93
- end
94
-
95
- def make_empty(sym)
96
- case sym
97
- when :hash
98
- {}
99
- when :array
100
- []
101
- end
102
- end
103
-
104
- def each_entry_helper(coll, path, last_key, &block)
105
- next_path = if last_key
106
- path + [last_key]
107
- else
108
- path
109
- end
110
-
111
- case coll
112
- when Hash
113
- coll.each_pair do |key, value|
114
- each_entry_helper(value, next_path, key, &block)
115
- end
116
-
117
- when Array
118
- coll.each_with_index do |element, idx|
119
- each_entry_helper(element, next_path, idx, &block)
120
- end
121
-
122
- when String
123
- yield coll, path, last_key
124
- end
125
- end
126
- end
127
- end