abroad 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +142 -0
- data/abroad.gemspec +25 -0
- data/lib/abroad/extractors/extractor.rb +46 -0
- data/lib/abroad/extractors/json/json_extractor.rb +17 -0
- data/lib/abroad/extractors/json/key_value_extractor.rb +38 -0
- data/lib/abroad/extractors/json.rb +8 -0
- data/lib/abroad/extractors/xml/android_extractor.rb +113 -0
- data/lib/abroad/extractors/xml/xml_extractor.rb +28 -0
- data/lib/abroad/extractors/xml.rb +8 -0
- data/lib/abroad/extractors/yaml/dotted_key_extractor.rb +40 -0
- data/lib/abroad/extractors/yaml/jruby_compat.rb +170 -0
- data/lib/abroad/extractors/yaml/rails_extractor.rb +15 -0
- data/lib/abroad/extractors/yaml/yaml_extractor.rb +28 -0
- data/lib/abroad/extractors/yaml.rb +9 -0
- data/lib/abroad/extractors.rb +28 -0
- data/lib/abroad/serializers/json/json_serializer.rb +27 -0
- data/lib/abroad/serializers/json/key_value_serializer.rb +20 -0
- data/lib/abroad/serializers/json.rb +8 -0
- data/lib/abroad/serializers/serializer.rb +52 -0
- data/lib/abroad/serializers/trie.rb +76 -0
- data/lib/abroad/serializers/xml/android_serializer.rb +143 -0
- data/lib/abroad/serializers/xml/xml_serializer.rb +23 -0
- data/lib/abroad/serializers/xml.rb +8 -0
- data/lib/abroad/serializers/yaml/rails_serializer.rb +110 -0
- data/lib/abroad/serializers/yaml/yaml_serializer.rb +19 -0
- data/lib/abroad/serializers/yaml.rb +8 -0
- data/lib/abroad/serializers.rb +29 -0
- data/lib/abroad/version.rb +3 -0
- data/lib/abroad.rb +37 -0
- data/lib/ext/htmlentities/android_xml_decoder.rb +15 -0
- data/lib/ext/htmlentities/android_xml_encoder.rb +23 -0
- data/spec/abroad_spec.rb +35 -0
- data/spec/extractors/json/fixtures/arrays.json +9 -0
- data/spec/extractors/json/fixtures/basic.json +5 -0
- data/spec/extractors/json/fixtures/objects.json +11 -0
- data/spec/extractors/json/fixtures.yml +22 -0
- data/spec/extractors/json/json_extractor_spec.rb +6 -0
- data/spec/extractors/xml/fixtures/basic_arrays.xml +9 -0
- data/spec/extractors/xml/fixtures/basic_plurals.xml +8 -0
- data/spec/extractors/xml/fixtures/basic_strings.xml +8 -0
- data/spec/extractors/xml/fixtures/entities.xml +4 -0
- data/spec/extractors/xml/fixtures/markup.xml +5 -0
- data/spec/extractors/xml/fixtures/newlines.xml +6 -0
- data/spec/extractors/xml/fixtures/quotes.xml +9 -0
- data/spec/extractors/xml/fixtures.yml +54 -0
- data/spec/extractors/xml/xml_extractor_spec.rb +6 -0
- data/spec/extractors/yaml/fixtures/arrays.yml +9 -0
- data/spec/extractors/yaml/fixtures/arrays_and_hashes.yml +29 -0
- data/spec/extractors/yaml/fixtures/invalid_single_quote_escape.yml +2 -0
- data/spec/extractors/yaml/fixtures/invalid_single_quote_escape_array.yml +3 -0
- data/spec/extractors/yaml/fixtures/nesting.yml +19 -0
- data/spec/extractors/yaml/fixtures/short.yml +2 -0
- data/spec/extractors/yaml/fixtures.yml +75 -0
- data/spec/extractors/yaml/jruby_compat_spec.rb +54 -0
- data/spec/extractors/yaml/yaml_extractor_spec.rb +6 -0
- data/spec/serializers/json/key_value_serializer_spec.rb +26 -0
- data/spec/serializers/xml/android_serializer_spec.rb +165 -0
- data/spec/serializers/yaml/rails_serializer_spec.rb +171 -0
- data/spec/spec_helper.rb +43 -0
- metadata +186 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Abroad
|
4
|
+
module Extractors
|
5
|
+
module Yaml
|
6
|
+
|
7
|
+
class YamlExtractor < Extractor
|
8
|
+
private
|
9
|
+
|
10
|
+
def parse
|
11
|
+
YAML.load(clean_yaml(stream.read))
|
12
|
+
rescue Psych::SyntaxError => e
|
13
|
+
raise Abroad::SyntaxError, "Syntax error in yaml: #{e.message}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def clean_yaml(yaml_content)
|
17
|
+
if Abroad.jruby?
|
18
|
+
require 'abroad/extractors/yaml/jruby_compat'
|
19
|
+
JRubyCompat.clean(yaml_content)
|
20
|
+
else
|
21
|
+
yaml_content
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Abroad
|
2
|
+
module Extractors
|
3
|
+
module Yaml
|
4
|
+
autoload :DottedKeyExtractor, 'abroad/extractors/yaml/dotted_key_extractor'
|
5
|
+
autoload :RailsExtractor, 'abroad/extractors/yaml/rails_extractor'
|
6
|
+
autoload :YamlExtractor, 'abroad/extractors/yaml/yaml_extractor'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Abroad
|
2
|
+
module Extractors
|
3
|
+
autoload :Extractor, 'abroad/extractors/extractor'
|
4
|
+
autoload :Json, 'abroad/extractors/json'
|
5
|
+
autoload :Xml, 'abroad/extractors/xml'
|
6
|
+
autoload :Yaml, 'abroad/extractors/yaml'
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def register(id, klass)
|
10
|
+
registered[id.to_s] = klass
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(id)
|
14
|
+
registered[id.to_s]
|
15
|
+
end
|
16
|
+
|
17
|
+
def available
|
18
|
+
registered.keys
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def registered
|
24
|
+
@registered ||= {}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'json-write-stream'
|
2
|
+
|
3
|
+
module Abroad
|
4
|
+
module Serializers
|
5
|
+
module Json
|
6
|
+
|
7
|
+
class JsonSerializer < Serializer
|
8
|
+
attr_reader :writer
|
9
|
+
|
10
|
+
def initialize(stream, locale, encoding = Encoding::UTF_8)
|
11
|
+
super
|
12
|
+
@writer = JsonWriteStream.from_stream(stream, encoding)
|
13
|
+
end
|
14
|
+
|
15
|
+
def write_raw(text)
|
16
|
+
writer.stream.write(text)
|
17
|
+
end
|
18
|
+
|
19
|
+
def flush
|
20
|
+
writer.flush
|
21
|
+
stream.flush
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Abroad
|
2
|
+
module Serializers
|
3
|
+
module Json
|
4
|
+
|
5
|
+
class KeyValueSerializer < JsonSerializer
|
6
|
+
def initialize(stream, locale, encoding = Encoding::UTF_8)
|
7
|
+
super
|
8
|
+
writer.write_object
|
9
|
+
end
|
10
|
+
|
11
|
+
def write_key_value(key, value)
|
12
|
+
writer.write_key_value(
|
13
|
+
key.encode(encoding), value.encode(encoding)
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Abroad
|
2
|
+
module Serializers
|
3
|
+
|
4
|
+
class Serializer
|
5
|
+
attr_reader :stream, :locale, :encoding
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def from_stream(stream, locale)
|
9
|
+
serializer = new(stream, locale)
|
10
|
+
|
11
|
+
if block_given?
|
12
|
+
yield(serializer).tap do
|
13
|
+
serializer.close
|
14
|
+
end
|
15
|
+
else
|
16
|
+
serializer
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def open(file, locale, &block)
|
21
|
+
from_stream(File.open(file), locale, &block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(stream, locale, encoding = Encoding::UTF_8)
|
26
|
+
@stream = stream
|
27
|
+
@locale = locale
|
28
|
+
@encoding = encoding
|
29
|
+
end
|
30
|
+
|
31
|
+
def write_key_value(key, value)
|
32
|
+
raise NotImplementedError,
|
33
|
+
'expected to be implemented in derived classes'
|
34
|
+
end
|
35
|
+
|
36
|
+
def write_raw(text)
|
37
|
+
raise NotImplementedError,
|
38
|
+
'expected to be implemented in derived classes'
|
39
|
+
end
|
40
|
+
|
41
|
+
def flush
|
42
|
+
stream.flush
|
43
|
+
end
|
44
|
+
|
45
|
+
def close
|
46
|
+
flush
|
47
|
+
stream.close
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Abroad
|
2
|
+
module Serializers
|
3
|
+
|
4
|
+
class Trie
|
5
|
+
attr_reader :root
|
6
|
+
|
7
|
+
def initialize(root = nil)
|
8
|
+
@root = root || TrieNode.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def add(key_enum, value)
|
12
|
+
node = root
|
13
|
+
|
14
|
+
key_enum.each do |key|
|
15
|
+
if node.has_child?(key)
|
16
|
+
node = node.child_at(key)
|
17
|
+
else
|
18
|
+
node = node.add_child(key, TrieNode.new)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
node.value = value
|
23
|
+
end
|
24
|
+
|
25
|
+
def find(key_enum)
|
26
|
+
node = root
|
27
|
+
key_enum.each do |key|
|
28
|
+
node = node.child_at(key)
|
29
|
+
return nil unless node
|
30
|
+
end
|
31
|
+
node.value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class TrieNode
|
36
|
+
NO_VALUE = :__novalue__
|
37
|
+
|
38
|
+
attr_reader :children
|
39
|
+
attr_accessor :value
|
40
|
+
|
41
|
+
def initialize(value = NO_VALUE)
|
42
|
+
@value = value
|
43
|
+
@children = {}
|
44
|
+
end
|
45
|
+
|
46
|
+
def each_child
|
47
|
+
if block_given?
|
48
|
+
children.each_pair { |key, child| yield key, child }
|
49
|
+
else
|
50
|
+
children.each
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def has_children?
|
55
|
+
!children.empty?
|
56
|
+
end
|
57
|
+
|
58
|
+
def has_child?(key)
|
59
|
+
children.include?(key)
|
60
|
+
end
|
61
|
+
|
62
|
+
def child_at(key)
|
63
|
+
children[key]
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_child(key, node)
|
67
|
+
@children[key] = node
|
68
|
+
end
|
69
|
+
|
70
|
+
def has_value?
|
71
|
+
value != NO_VALUE
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require 'htmlentities'
|
2
|
+
require 'ext/htmlentities/android_xml_encoder'
|
3
|
+
|
4
|
+
module Abroad
|
5
|
+
module Serializers
|
6
|
+
module Xml
|
7
|
+
|
8
|
+
class AndroidSerializer < XmlSerializer
|
9
|
+
PLURAL_FORMS = %w(
|
10
|
+
zero one two few many other
|
11
|
+
)
|
12
|
+
|
13
|
+
attr_reader :plurals, :arrays
|
14
|
+
|
15
|
+
def after_initialize
|
16
|
+
writer.open_tag('resources')
|
17
|
+
@plurals = Hash.new { |hash, key| hash[key] = {} }
|
18
|
+
@arrays = Hash.new { |hash, key| hash[key] = {} }
|
19
|
+
end
|
20
|
+
|
21
|
+
def write_raw(text)
|
22
|
+
stream.write(text)
|
23
|
+
end
|
24
|
+
|
25
|
+
def write_key_value(key, value)
|
26
|
+
key_parts = split_key(key)
|
27
|
+
|
28
|
+
case detect_string_type(key_parts)
|
29
|
+
when :plural
|
30
|
+
record_plural(key_parts, value)
|
31
|
+
when :array_element
|
32
|
+
record_array_element(key_parts, value)
|
33
|
+
else
|
34
|
+
write_string(key, value)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def flush
|
39
|
+
write_recorded_plurals
|
40
|
+
write_recorded_arrays
|
41
|
+
writer.flush
|
42
|
+
stream.flush
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def split_key(key)
|
48
|
+
if idx = key.rindex('.')
|
49
|
+
[key[0..(idx - 1)], key[(idx + 1)..-1]]
|
50
|
+
else
|
51
|
+
# this case should never happen
|
52
|
+
[key, '']
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def record_plural(key_parts, value)
|
57
|
+
plurals[key_parts.first][key_parts.last] = value
|
58
|
+
end
|
59
|
+
|
60
|
+
def record_array_element(key_parts, value)
|
61
|
+
arrays[key_parts.first][key_parts.last.to_i] = value
|
62
|
+
end
|
63
|
+
|
64
|
+
def write_plural(name, plural_forms)
|
65
|
+
writer.open_tag(:plurals, name: name)
|
66
|
+
|
67
|
+
plural_forms.each_pair do |quantity, value|
|
68
|
+
writer.open_single_line_tag(:item, quantity: quantity)
|
69
|
+
write_text(value)
|
70
|
+
writer.close_tag
|
71
|
+
end
|
72
|
+
|
73
|
+
writer.close_tag
|
74
|
+
end
|
75
|
+
|
76
|
+
def write_array(name, array_elements)
|
77
|
+
writer.open_tag(:'string-array', name: name)
|
78
|
+
count = array_elements.keys.max
|
79
|
+
|
80
|
+
(0..count).each do |i|
|
81
|
+
writer.open_single_line_tag(:item)
|
82
|
+
write_text(array_elements[i] || '')
|
83
|
+
writer.close_tag
|
84
|
+
end
|
85
|
+
|
86
|
+
writer.close_tag
|
87
|
+
end
|
88
|
+
|
89
|
+
def write_recorded_plurals
|
90
|
+
plurals.each_pair do |name, plural_forms|
|
91
|
+
write_plural(name, plural_forms)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def write_recorded_arrays
|
96
|
+
arrays.each_pair do |name, array_elements|
|
97
|
+
write_array(name, array_elements)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def write_string(key, value)
|
102
|
+
writer.open_single_line_tag(:string, name: key)
|
103
|
+
write_text(value)
|
104
|
+
writer.close_tag
|
105
|
+
end
|
106
|
+
|
107
|
+
def write_text(text)
|
108
|
+
escaped_text = escape(text)
|
109
|
+
writer.write_text(
|
110
|
+
escaped_text, escape: false
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
def detect_string_type(key_parts)
|
115
|
+
last_part = key_parts.last
|
116
|
+
|
117
|
+
if PLURAL_FORMS.include?(last_part)
|
118
|
+
:plural
|
119
|
+
elsif last_part =~ /\A[\d]+\z/
|
120
|
+
:array_element
|
121
|
+
else
|
122
|
+
:string
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def escape(text)
|
127
|
+
text.gsub!("\n", "\\n") # escape literal newlines
|
128
|
+
text.gsub!("\r", "\\r") # escape literal carriage returns
|
129
|
+
text.gsub!("\t", "\\t") # escape literal tabs
|
130
|
+
text.gsub!(/([^\\]?)(')/) { "#{$1}\\'" } # escape single quotes
|
131
|
+
text.gsub!(/([^\\]?)(")/) { "#{$1}\\\"" } # escape double quotes
|
132
|
+
|
133
|
+
coder.encode(text)
|
134
|
+
end
|
135
|
+
|
136
|
+
def coder
|
137
|
+
@coder ||= HTMLEntities::AndroidXmlEncoder.new
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'xml-write-stream'
|
2
|
+
|
3
|
+
module Abroad
|
4
|
+
module Serializers
|
5
|
+
module Xml
|
6
|
+
|
7
|
+
class XmlSerializer < Serializer
|
8
|
+
attr_reader :writer
|
9
|
+
|
10
|
+
def initialize(stream, locale, encoding = Encoding::UTF_8)
|
11
|
+
super
|
12
|
+
@writer = XmlWriteStream.from_stream(stream)
|
13
|
+
writer.write_header(encoding: encoding.to_s)
|
14
|
+
after_initialize
|
15
|
+
end
|
16
|
+
|
17
|
+
def after_initialize
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Abroad
|
2
|
+
module Serializers
|
3
|
+
module Yaml
|
4
|
+
|
5
|
+
class RailsSerializer < YamlSerializer
|
6
|
+
attr_reader :trie
|
7
|
+
|
8
|
+
def initialize(stream, locale, encoding = Encoding::UTF_8)
|
9
|
+
super
|
10
|
+
@trie = Abroad::Serializers::Trie.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def write_raw(text)
|
14
|
+
writer.stream.write(text)
|
15
|
+
end
|
16
|
+
|
17
|
+
def write_key_value(key, value)
|
18
|
+
key_parts = split_key(key)
|
19
|
+
encoded_value = value.encode(encoding)
|
20
|
+
trie.add(key_parts, encoded_value)
|
21
|
+
end
|
22
|
+
|
23
|
+
def flush
|
24
|
+
writer.write_map(locale)
|
25
|
+
write_node(trie.root, locale)
|
26
|
+
writer.flush
|
27
|
+
stream.flush
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def split_key(key)
|
33
|
+
# Doesn't allow dots to come before spaces or at the end of the key.
|
34
|
+
# Uses regex negative lookahead, that's what the (?!) sections are.
|
35
|
+
# Examples:
|
36
|
+
# 'timezones.Solomon Is.' => ['timezones', 'Solomon Is.']
|
37
|
+
# 'timezones.Solomon Is.foo' => ['timezones', 'Solomon Is', 'foo']
|
38
|
+
# 'timezones.Solomon Is..foo' => ['timezones', 'Solomon Is.', 'foo']
|
39
|
+
key.split(/\.(?!\s)(?!\z)(?!\.)/)
|
40
|
+
end
|
41
|
+
|
42
|
+
# depth-first
|
43
|
+
def write_node(node, parent_key)
|
44
|
+
if node
|
45
|
+
if node.has_children?
|
46
|
+
if children_are_sequence(node)
|
47
|
+
write_sequence(node, parent_key)
|
48
|
+
else
|
49
|
+
write_map(node, parent_key)
|
50
|
+
end
|
51
|
+
elsif node.has_value?
|
52
|
+
write_value(node, parent_key)
|
53
|
+
end
|
54
|
+
else
|
55
|
+
write_value(node, parent_key)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def write_value(node, parent_key)
|
60
|
+
value = node ? node.value : ''
|
61
|
+
if writer.in_map?
|
62
|
+
writer.write_key_value(parent_key, value)
|
63
|
+
else
|
64
|
+
writer.write_element(value)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def write_map(node, parent_key)
|
69
|
+
if writer.in_map?
|
70
|
+
writer.write_map(parent_key)
|
71
|
+
else
|
72
|
+
writer.write_map
|
73
|
+
end
|
74
|
+
|
75
|
+
node.each_child do |key, child|
|
76
|
+
write_node(child, key)
|
77
|
+
end
|
78
|
+
|
79
|
+
writer.close_map
|
80
|
+
end
|
81
|
+
|
82
|
+
def write_sequence(node, parent_key)
|
83
|
+
if writer.in_map?
|
84
|
+
writer.write_sequence(parent_key)
|
85
|
+
else
|
86
|
+
writer.write_sequence
|
87
|
+
end
|
88
|
+
|
89
|
+
generate_sequence(node).each do |element|
|
90
|
+
write_node(element, nil)
|
91
|
+
end
|
92
|
+
|
93
|
+
writer.close_sequence
|
94
|
+
end
|
95
|
+
|
96
|
+
def children_are_sequence(node)
|
97
|
+
node.children.all? { |key, _| key =~ /\A[\d]+\z/ }
|
98
|
+
end
|
99
|
+
|
100
|
+
def generate_sequence(node)
|
101
|
+
keys = node.children.keys.map(&:to_i)
|
102
|
+
keys.each_with_object(Array.new(keys.max)) do |idx, arr|
|
103
|
+
arr[idx] = node.children[idx.to_s]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'yaml-write-stream'
|
3
|
+
|
4
|
+
module Abroad
|
5
|
+
module Serializers
|
6
|
+
module Yaml
|
7
|
+
|
8
|
+
class YamlSerializer < Serializer
|
9
|
+
attr_reader :writer
|
10
|
+
|
11
|
+
def initialize(stream, locale, encoding = Encoding::UTF_8)
|
12
|
+
super
|
13
|
+
@writer = YamlWriteStream.from_stream(stream, encoding)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Abroad
|
2
|
+
module Serializers
|
3
|
+
autoload :Json, 'abroad/serializers/json'
|
4
|
+
autoload :Serializer, 'abroad/serializers/serializer'
|
5
|
+
autoload :Trie, 'abroad/serializers/trie'
|
6
|
+
autoload :Xml, 'abroad/serializers/xml'
|
7
|
+
autoload :Yaml, 'abroad/serializers/yaml'
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def register(id, klass)
|
11
|
+
registered[id] = klass
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(id)
|
15
|
+
registered[id]
|
16
|
+
end
|
17
|
+
|
18
|
+
def available
|
19
|
+
registered.keys
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def registered
|
25
|
+
@registered ||= {}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/abroad.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Abroad
|
2
|
+
class SyntaxError < StandardError; end
|
3
|
+
|
4
|
+
autoload :Extractors, 'abroad/extractors'
|
5
|
+
autoload :Serializers, 'abroad/serializers'
|
6
|
+
|
7
|
+
Extractors.register('yaml/rails', Extractors::Yaml::RailsExtractor)
|
8
|
+
Extractors.register('yaml/dotted-key', Extractors::Yaml::DottedKeyExtractor)
|
9
|
+
Extractors.register('json/key-value', Extractors::Json::KeyValueExtractor)
|
10
|
+
Extractors.register('xml/android', Extractors::Xml::AndroidExtractor)
|
11
|
+
|
12
|
+
Serializers.register('yaml/rails', Serializers::Yaml::RailsSerializer)
|
13
|
+
Serializers.register('json/key-value', Serializers::Json::KeyValueSerializer)
|
14
|
+
Serializers.register('xml/android', Serializers::Xml::AndroidSerializer)
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def extractors
|
18
|
+
Extractors.available
|
19
|
+
end
|
20
|
+
|
21
|
+
def extractor(id)
|
22
|
+
Extractors.get(id)
|
23
|
+
end
|
24
|
+
|
25
|
+
def serializers
|
26
|
+
Serializers.available
|
27
|
+
end
|
28
|
+
|
29
|
+
def serializer(id)
|
30
|
+
Serializers.get(id)
|
31
|
+
end
|
32
|
+
|
33
|
+
def jruby?
|
34
|
+
RUBY_ENGINE == 'jruby'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'htmlentities'
|
2
|
+
|
3
|
+
class HTMLEntities
|
4
|
+
MAPPINGS['android_xml'] = MAPPINGS['xhtml1'].dup.tap do |mappings|
|
5
|
+
mappings.delete('apos')
|
6
|
+
end
|
7
|
+
|
8
|
+
FLAVORS << 'android_xml'
|
9
|
+
|
10
|
+
class AndroidXmlDecoder < Decoder
|
11
|
+
def initialize
|
12
|
+
super('android_xml')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'htmlentities'
|
2
|
+
|
3
|
+
class HTMLEntities
|
4
|
+
MAPPINGS['android_xml'] = MAPPINGS['xhtml1'].dup.tap do |mappings|
|
5
|
+
mappings.delete('apos')
|
6
|
+
end
|
7
|
+
|
8
|
+
FLAVORS << 'android_xml'
|
9
|
+
|
10
|
+
class AndroidXmlEncoder < Encoder
|
11
|
+
def initialize(instructions = [])
|
12
|
+
super('android_xml', instructions)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
# had to adjust this so that single and double quotes don't get turned into
|
18
|
+
# entities (they're escaped by hand with backslashes)
|
19
|
+
def basic_entity_regexp
|
20
|
+
@basic_entity_regexp ||= /[&]/
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|