cwyckoff-babel_icious 0.0.1 → 0.0.2
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.
- data/README.rdoc +2 -2
- data/init.rb +1 -0
- data/lib/babel_icious/core_ext/enumerable.rb +9 -0
- data/lib/babel_icious/hash_map.rb +36 -0
- data/lib/babel_icious/map_factory.rb +19 -0
- data/lib/babel_icious/mapper.rb +52 -0
- data/lib/babel_icious/path_translator.rb +35 -0
- data/lib/babel_icious/target_mapper.rb +54 -0
- data/lib/babel_icious/xml_map.rb +63 -0
- data/lib/babel_icious.rb +12 -0
- metadata +13 -3
data/README.rdoc
CHANGED
@@ -17,7 +17,7 @@ Add a mapper for JSON.
|
|
17
17
|
|
18
18
|
Mappings are set up by calling passing mapping 'coordinates' to a 'config' block on the Mapper class:
|
19
19
|
|
20
|
-
Mapper.config(:foo) do |m|
|
20
|
+
Babelicious::Mapper.config(:foo) do |m|
|
21
21
|
|
22
22
|
m.direction = {:from => :xml, :to => :hash}
|
23
23
|
|
@@ -49,7 +49,7 @@ with the value of "bar" from the hash above placed in the nested <foo> tags in t
|
|
49
49
|
|
50
50
|
When you want to translate the mappings, simply call:
|
51
51
|
|
52
|
-
Mapper.translate(:foo, source)
|
52
|
+
Babelicious::Mapper.translate(:foo, source)
|
53
53
|
|
54
54
|
passing the tag for the mapping and the actual source you want to translate from.
|
55
55
|
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "lib", "babel_icious")
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# http://rpheath.com/posts/341-ruby-inject-with-index
|
2
|
+
unless Array.instance_methods.include?("inject_with_index")
|
3
|
+
module Enumerable
|
4
|
+
def inject_with_index(injected)
|
5
|
+
each_with_index{ |obj, index| injected = yield(injected, obj, index) }
|
6
|
+
injected
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Babelicious
|
2
|
+
|
3
|
+
class HashMap
|
4
|
+
|
5
|
+
def initialize(path_translator)
|
6
|
+
@path_translator = path_translator
|
7
|
+
end
|
8
|
+
|
9
|
+
def map_from(hash_output, source_value)
|
10
|
+
catch :no_value do
|
11
|
+
@path_translator.inject_with_index(hash_output) do |hsh, element, index|
|
12
|
+
if(hsh[element])
|
13
|
+
hsh[element]
|
14
|
+
else
|
15
|
+
hsh[element] = (index == @path_translator.last_index ? source_value : {})
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def value_from(source)
|
22
|
+
hash = {}
|
23
|
+
@path_translator.inject_with_index(hash) do |hsh, element, index|
|
24
|
+
return hsh[element.to_sym] if (index == @path_translator.last_index)
|
25
|
+
if hsh.empty?
|
26
|
+
source[element.to_sym]
|
27
|
+
else
|
28
|
+
hsh[element.to_sym]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Babelicious
|
2
|
+
|
3
|
+
class MapFactory
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def source(direction, opts={})
|
8
|
+
eval("Babelicious::#{direction[:from].to_s.capitalize}Map").new(PathTranslator.new(opts[:from]))
|
9
|
+
end
|
10
|
+
|
11
|
+
def target(direction, opts={})
|
12
|
+
eval("Babelicious::#{direction[:to].to_s.capitalize}Map").new(PathTranslator.new(opts[:to]))
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class MapperError < Exception; end
|
2
|
+
|
3
|
+
module Babelicious
|
4
|
+
|
5
|
+
class Mapper
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_reader :direction, :current_target_map_key
|
9
|
+
|
10
|
+
def config(key)
|
11
|
+
raise MapperError, "A mapping for the key #{key} currently exists. Are you sure you want to merge the mapping you are about to do with the existing mapping?" if mapping_already_exists?(key)
|
12
|
+
|
13
|
+
@current_target_map_key = key
|
14
|
+
yield self
|
15
|
+
end
|
16
|
+
|
17
|
+
def direction=(dir={})
|
18
|
+
current_target_mapper.direction = dir
|
19
|
+
end
|
20
|
+
|
21
|
+
def map(opts={})
|
22
|
+
current_target_mapper.register_mapping(opts)
|
23
|
+
end
|
24
|
+
|
25
|
+
def mappings
|
26
|
+
@mapped_targets ||= {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def reset
|
30
|
+
@mapped_targets, @direction = nil, nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def translate(key=nil, source=nil)
|
34
|
+
raise MapperError, "No target mapper exists for key #{key}" unless mappings.has_key?(key)
|
35
|
+
|
36
|
+
mappings[key].map(source)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def current_target_mapper
|
42
|
+
mappings[@current_target_map_key] ||= (mappings[@current_target_map_key] = TargetMapper.new)
|
43
|
+
end
|
44
|
+
|
45
|
+
def mapping_already_exists?(key)
|
46
|
+
mappings.keys.include?(key)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Babelicious
|
2
|
+
|
3
|
+
class PathTranslator
|
4
|
+
attr_reader :parsed_path, :full_path
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(untranslated_path)
|
8
|
+
@full_path = untranslated_path
|
9
|
+
@parsed_path = translate(untranslated_path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](index)
|
13
|
+
@parsed_path[index]
|
14
|
+
end
|
15
|
+
|
16
|
+
def each(&block)
|
17
|
+
@parsed_path.each(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def last_index
|
21
|
+
@parsed_path.size - 1
|
22
|
+
end
|
23
|
+
|
24
|
+
def size
|
25
|
+
@parsed_path.size
|
26
|
+
end
|
27
|
+
|
28
|
+
def translate(untranslated_path)
|
29
|
+
untranslated_path.gsub(/^\//, "").split("/")
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class TargetMapperError < Exception; end
|
2
|
+
|
3
|
+
module Babelicious
|
4
|
+
|
5
|
+
class TargetMapper
|
6
|
+
attr_reader :mappings, :direction
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@mappings = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def direction=(dir)
|
13
|
+
raise TargetMapperError, "Direction must be a hash" unless dir.is_a?(Hash)
|
14
|
+
raise TargetMapperError, "Both :from and :to keys must be set (e.g., {:from => :xml, :to => :hash}" unless (dir[:from] && dir[:to])
|
15
|
+
|
16
|
+
@direction = dir
|
17
|
+
end
|
18
|
+
|
19
|
+
def map(source)
|
20
|
+
target = initial_target
|
21
|
+
@mappings.each do |source_element, target_element|
|
22
|
+
source_value = source_element.value_from(source)
|
23
|
+
target_element.map_from(target, source_value)
|
24
|
+
end
|
25
|
+
target
|
26
|
+
end
|
27
|
+
|
28
|
+
def register_mapping(opts={})
|
29
|
+
raise TargetMapperError, "Both :from and :to keys must be set (e.g., {:from => \"foo/bar\", :to => \"bar/foo\")" unless (opts[:from] && opts[:to])
|
30
|
+
|
31
|
+
@mappings << [MapFactory.source(@direction, opts), MapFactory.target(@direction, opts)]
|
32
|
+
end
|
33
|
+
|
34
|
+
def reset
|
35
|
+
@mappings, @direction = [], nil
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def initial_target
|
42
|
+
raise TargetMapperError, "please set @direction (e.g., target_mapper.direction = {:from => :xml, :to => :hash}" unless @direction
|
43
|
+
|
44
|
+
case @direction[:to]
|
45
|
+
when :xml
|
46
|
+
XML::Document.new()
|
47
|
+
when :hash
|
48
|
+
{}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'xml'
|
2
|
+
|
3
|
+
module Babelicious
|
4
|
+
|
5
|
+
class XmlMap
|
6
|
+
|
7
|
+
def initialize(path_translator)
|
8
|
+
@path_translator = path_translator
|
9
|
+
end
|
10
|
+
|
11
|
+
def value_from(source)
|
12
|
+
source.find("/#{@path_translator.full_path}").each do |node|
|
13
|
+
return node.content
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def map_from(xml_output, source_value)
|
18
|
+
@index = @path_translator.last_index
|
19
|
+
|
20
|
+
set_root(xml_output)
|
21
|
+
|
22
|
+
unless(update_node?(xml_output, source_value))
|
23
|
+
populate_nodes(xml_output)
|
24
|
+
map_from(xml_output, source_value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def populate_nodes(xml_output)
|
31
|
+
return if @index == 0
|
32
|
+
|
33
|
+
if(node = previous_node(xml_output))
|
34
|
+
new_node = XML::Node.new(@path_translator[@index+1])
|
35
|
+
node << new_node
|
36
|
+
else
|
37
|
+
populate_nodes(xml_output)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def previous_node(xml_output)
|
42
|
+
@index -= 1
|
43
|
+
node = xml_output.find("//#{@path_translator[0..@index].join("/")}")
|
44
|
+
node[0]
|
45
|
+
end
|
46
|
+
|
47
|
+
def set_root(xml_output)
|
48
|
+
if xml_output.root.nil?
|
49
|
+
xml_output.root = XML::Node.new(@path_translator[0])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def update_node?(xml_output, source_value)
|
54
|
+
node = xml_output.find("/#{@path_translator.full_path}")
|
55
|
+
unless(node.empty?)
|
56
|
+
node[0] << source_value.strip
|
57
|
+
return true
|
58
|
+
end
|
59
|
+
false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
data/lib/babel_icious.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'xml'
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
|
5
|
+
|
6
|
+
require "babel_icious/core_ext/enumerable"
|
7
|
+
require "babel_icious/target_mapper"
|
8
|
+
require "babel_icious/map_factory"
|
9
|
+
require "babel_icious/path_translator"
|
10
|
+
require "babel_icious/xml_map"
|
11
|
+
require "babel_icious/hash_map"
|
12
|
+
require "babel_icious/mapper"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cwyckoff-babel_icious
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Wyckoff
|
@@ -31,8 +31,18 @@ extensions: []
|
|
31
31
|
extra_rdoc_files:
|
32
32
|
- README.rdoc
|
33
33
|
- MIT-LICENSE
|
34
|
-
files:
|
35
|
-
|
34
|
+
files:
|
35
|
+
- init.rb
|
36
|
+
- lib/babel_icious.rb
|
37
|
+
- lib/babel_icious/hash_map.rb
|
38
|
+
- lib/babel_icious/map_factory.rb
|
39
|
+
- lib/babel_icious/xml_map.rb
|
40
|
+
- lib/babel_icious/mapper.rb
|
41
|
+
- lib/babel_icious/path_translator.rb
|
42
|
+
- lib/babel_icious/target_mapper.rb
|
43
|
+
- lib/babel_icious/core_ext/enumerable.rb
|
44
|
+
- README.rdoc
|
45
|
+
- MIT-LICENSE
|
36
46
|
has_rdoc: true
|
37
47
|
homepage: http://github.com/cwyckoff/babel_icious
|
38
48
|
post_install_message:
|