Initial commit

This commit is contained in:
Yann Esposito (Yogsototh) 2012-02-28 15:38:11 +01:00
commit ad89dd5ccc
4 changed files with 457 additions and 0 deletions

210
deepmergecore.rb Executable file
View file

@ -0,0 +1,210 @@
module DeepMerge
class InvalidParameter < StandardError; end
DEFAULT_FIELD_KNOCKOUT_PREFIX = '--'
# Deep Merge core documentation.
# deep_merge! method permits merging of arbitrary child elements. The two top level
# elements must be hashes. These hashes can contain unlimited (to stack limit) levels
# of child elements. These child elements to not have to be of the same types.
# Where child elements are of the same type, deep_merge will attempt to merge them together.
# Where child elements are not of the same type, deep_merge will skip or optionally overwrite
# the destination element with the contents of the source element at that level.
# So if you have two hashes like this:
# source = {:x => [1,2,3], :y => 2}
# dest = {:x => [4,5,'6'], :y => [7,8,9]}
# dest.deep_merge!(source)
# Results: {:x => [1,2,3,4,5,'6'], :y => 2}
# By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
# To avoid this, use "deep_merge" (no bang/exclamation mark)
#
# Options:
# Options are specified in the last parameter passed, which should be in hash format:
# hash.deep_merge!({:x => [1,2]}, {:knockout_prefix => '--'})
# :preserve_unmergeables DEFAULT: false
# Set to true to skip any unmergeable elements from source
# :knockout_prefix DEFAULT: nil
# Set to string value to signify prefix which deletes elements from existing element
# :sort_merged_arrays DEFAULT: false
# Set to true to sort all arrays that are merged together
# :unpack_arrays DEFAULT: nil
# Set to string value to run "Array::join" then "String::split" against all arrays
# :merge_hash_arrays DEFAULT: false
# Set to true to merge hashes within arrays
# :merge_debug DEFAULT: false
# Set to true to get console output of merge process for debugging
#
# Selected Options Details:
# :knockout_prefix => The purpose of this is to provide a way to remove elements
# from existing Hash by specifying them in a special way in incoming hash
# source = {:x => ['--1', '2']}
# dest = {:x => ['1', '3']}
# dest.ko_deep_merge!(source)
# Results: {:x => ['2','3']}
# Additionally, if the knockout_prefix is passed alone as a string, it will cause
# the entire element to be removed:
# source = {:x => '--'}
# dest = {:x => [1,2,3]}
# dest.ko_deep_merge!(source)
# Results: {:x => ""}
# :unpack_arrays => The purpose of this is to permit compound elements to be passed
# in as strings and to be converted into discrete array elements
# irsource = {:x => ['1,2,3', '4']}
# dest = {:x => ['5','6','7,8']}
# dest.deep_merge!(source, {:unpack_arrays => ','})
# Results: {:x => ['1','2','3','4','5','6','7','8'}
# Why: If receiving data from an HTML form, this makes it easy for a checkbox
# to pass multiple values from within a single HTML element
#
# :merge_hash_arrays => merge hashes within arrays
# source = {:x => [{:y => 1}]}
# dest = {:x => [{:z => 2}]}
# dest.deep_merge!(source, {:merge_hash_arrays => true})
# Results: {:x => [{:y => 1, :z => 2}]}
#
# There are many tests for this library - and you can learn more about the features
# and usages of deep_merge! by just browsing the test examples
def self.deep_merge!(source, dest, options = {})
# turn on this line for stdout debugging text
merge_debug = options[:merge_debug] || false
overwrite_unmergeable = !options[:preserve_unmergeables]
knockout_prefix = options[:knockout_prefix] || nil
raise InvalidParameter, "knockout_prefix cannot be an empty string in deep_merge!" if knockout_prefix == ""
raise InvalidParameter, "overwrite_unmergeable must be true if knockout_prefix is specified in deep_merge!" if knockout_prefix && !overwrite_unmergeable
# if present: we will split and join arrays on this char before merging
array_split_char = options[:unpack_arrays] || false
# request that we sort together any arrays when they are merged
sort_merged_arrays = options[:sort_merged_arrays] || false
# request that arrays of hashes are merged together
merge_hash_arrays = options[:merge_hash_arrays] || false
di = options[:debug_indent] || ''
# do nothing if source is nil
return dest if source.nil?
# if dest doesn't exist, then simply copy source to it
if !(dest) && overwrite_unmergeable
dest = source; return dest
end
puts "#{di}Source class: #{source.class.inspect} :: Dest class: #{dest.class.inspect}" if merge_debug
if source.kind_of?(Hash)
puts "#{di}Hashes: #{source.inspect} :: #{dest.inspect}" if merge_debug
source.each do |src_key, src_value|
if dest.kind_of?(Hash)
puts "#{di} looping: #{src_key.inspect} => #{src_value.inspect} :: #{dest.inspect}" if merge_debug
if dest[src_key]
puts "#{di} ==>merging: #{src_key.inspect} => #{src_value.inspect} :: #{dest[src_key].inspect}" if merge_debug
dest[src_key] = deep_merge!(src_value, dest[src_key], options.merge(:debug_indent => di + ' '))
else # dest[src_key] doesn't exist so we want to create and overwrite it (but we do this via deep_merge!)
puts "#{di} ==>merging over: #{src_key.inspect} => #{src_value.inspect}" if merge_debug
# note: we rescue here b/c some classes respond to "dup" but don't implement it (Numeric, TrueClass, FalseClass, NilClass among maybe others)
begin
src_dup = src_value.dup # we dup src_value if possible because we're going to merge into it (since dest is empty)
rescue TypeError
src_dup = src_value
end
dest[src_key] = deep_merge!(src_value, src_dup, options.merge(:debug_indent => di + ' '))
end
else # dest isn't a hash, so we overwrite it completely (if permitted)
if overwrite_unmergeable
puts "#{di} overwriting dest: #{src_key.inspect} => #{src_value.inspect} -over-> #{dest.inspect}" if merge_debug
dest = overwrite_unmergeables(source, dest, options)
end
end
end
elsif source.kind_of?(Array)
puts "#{di}Arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
# if we are instructed, join/split any source arrays before processing
if array_split_char
puts "#{di} split/join on source: #{source.inspect}" if merge_debug
source = source.join(array_split_char).split(array_split_char)
if dest.kind_of?(Array)
dest = dest.join(array_split_char).split(array_split_char)
end
end
# if there's a naked knockout_prefix in source, that means we are to truncate dest
if source.index(knockout_prefix)
dest = clear_or_nil(dest); source.delete(knockout_prefix)
end
if dest.kind_of?(Array)
if knockout_prefix
print "#{di} knocking out: " if merge_debug
# remove knockout prefix items from both source and dest
source.delete_if do |ko_item|
retval = false
item = ko_item.respond_to?(:gsub) ? ko_item.gsub(%r{^#{knockout_prefix}}, "") : ko_item
if item != ko_item
print "#{ko_item} - " if merge_debug
dest.delete(item)
dest.delete(ko_item)
retval = true
end
retval
end
puts if merge_debug
end
puts "#{di} merging arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
source_all_hashes = source.all? { |i| i.kind_of?(Hash) }
dest_all_hashes = dest.all? { |i| i.kind_of?(Hash) }
if merge_hash_arrays && source_all_hashes && dest_all_hashes
# merge hashes in lists
list = []
dest.each_index do |i|
list[i] = deep_merge!(source[i] || {}, dest[i],
options.merge(:debug_indent => di + ' '))
end
list += source[dest.count..-1] if source.count > dest.count
dest = list
else
dest = dest | source
end
dest.sort! if sort_merged_arrays
elsif overwrite_unmergeable
puts "#{di} overwriting dest: #{source.inspect} -over-> #{dest.inspect}" if merge_debug
dest = overwrite_unmergeables(source, dest, options)
end
else # src_hash is not an array or hash, so we'll have to overwrite dest
puts "#{di}Others: #{source.inspect} :: #{dest.inspect}" if merge_debug
dest = overwrite_unmergeables(source, dest, options)
end
puts "#{di}Returning #{dest.inspect}" if merge_debug
dest
end # deep_merge!
# allows deep_merge! to uniformly handle overwriting of unmergeable entities
def self.overwrite_unmergeables(source, dest, options)
merge_debug = options[:merge_debug] || false
overwrite_unmergeable = !options[:preserve_unmergeables]
knockout_prefix = options[:knockout_prefix] || false
di = options[:debug_indent] || ''
if knockout_prefix && overwrite_unmergeable
if source.kind_of?(String) # remove knockout string from source before overwriting dest
src_tmp = source.gsub(%r{^#{knockout_prefix}},"")
elsif source.kind_of?(Array) # remove all knockout elements before overwriting dest
src_tmp = source.delete_if {|ko_item| ko_item.kind_of?(String) && ko_item.match(%r{^#{knockout_prefix}}) }
else
src_tmp = source
end
if src_tmp == source # if we didn't find a knockout_prefix then we just overwrite dest
puts "#{di}#{src_tmp.inspect} -over-> #{dest.inspect}" if merge_debug
dest = src_tmp
else # if we do find a knockout_prefix, then we just delete dest
puts "#{di}\"\" -over-> #{dest.inspect}" if merge_debug
dest = ""
end
elsif overwrite_unmergeable
dest = source
end
dest
end
def self.clear_or_nil(obj)
if obj.respond_to?(:clear)
obj.clear
else
obj = nil
end
obj
end
end # module DeepMerge

42
mustache2tpl.pl Executable file
View file

@ -0,0 +1,42 @@
#!/usr/bin/perl -p
BEGIN{print '<?xml version="1.0" encoding="utf-8"?><iw_pt><iw_perl><![CDATA[ sub protect { s#&#&amp;#g ; s#<#&lt;#; s#>#&gt;#g ; } ]]></iw_perl><![CDATA[';
my $i=0;
$pref="dcr";
}
my $close=']]>';
my $open='<![CDATA[';
# directories
s#{{jsdir}}#/FR/common/common/js/metapage#g;
s#{{cssdir}}#/FR/common/common/css/metapage#g;
s#{{imgdir}}#/FR/common/common/img/metapage#g;
# general
# {{# iteration }}
if (m!{{\#([^}]*)}}\s*$!) {
$old=$pref;
$pref .= "L";
s!{{\#([^}]*)}}\s*$!$close<iw_iterate var="$pref" list="$old.$1">$open!g;
}
# if must be on one line!
# {{# if }}
for (my $count=3; $count>0 ; $count--) {
s!{{\#([^}]*)}}(.*?){{/\1}}!$close<iw_if expr="{iw_value name='$pref.$1' /}"><iw_then>$open$2$close</iw_then></iw_if>$open!g;
s!{{\^([^}]*)}}(.*?){{/\1}}!$close<iw_if expr="\!{iw_value name='$pref.$1' /}"><iw_then>$open$2$close</iw_then></iw_if>$open!g;
}
# {{{...}}}
s#{{{([^\#\^\/][^}]*)}}}#$close<iw_value name="$pref.$1"/>$open#g;
# {{...}}
s#{{([^\#\^\/][^}]*)}}#$close<iw_ostream filter="protect()"><iw_value name="$pref.$1"/></iw_ostream>$open#g;
# {{/ iteration }}
if (m!{{\/([^}]*)}}\s*$!) {
chop($pref);
s!{{\/([^}]*)}}!$close</iw_iterate>$open!g;
}
END{print $close."</iw_pt>\n";}

77
yaml2dcr.rb Executable file
View file

@ -0,0 +1,77 @@
#!/usr/bin/env ruby
require "yaml"
filename=ARGV[0]
dcrname=ARGV[1]
# DCR PART
prefix=%{<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE record SYSTEM "dcr4.5.dtd">
<record name="#{dcrname}">
<item name="langue">
<value>fr</value>
</item>}
suffix=%{</record>}
def boolDCR(name,value)
if value then
%{<item name="#{name}"><value>#{name}</value></item>}
else
%{<item name="#{name}"/>}
end
end
def protect(str)
str.gsub('&','&amp;').gsub('<','&lt;').gsub('>','&gt;')
end
def stringDCR(name,value)
%{
<item name="#{name}">
<value>#{protect value}</value>
</item>}
end
def hashDCR(name,content)
%{
<item name="#{name}">
<value>#{
content.gsub(/^/,' ')}
</value>
</item>}
end
def arrayDCR(name,content)
%{
<item name="#{name}">#{
content.gsub(/^/,' ')}
</item>}
end
def yamlObj2XML( obj, tab="" )
res=""
obj.each do |k,v|
case v
when TrueClass
res <<= boolDCR(k,v)
when String
res <<= stringDCR(k,v)
when Hash
content=yamlObj2XML(v,"#{tab} ")
res <<= hashDCR(k,content)
when Array
content=""
v.each do |o|
content<<=%{
<value>
#{yamlObj2XML(o,"#{tab} ")}
</value>}
end
res <<= arrayDCR("#{k}", content)
else
puts "Else: #{v.class}"
end
end
return res
end
puts prefix
puts yamlObj2XML(YAML::load_file(filename))
puts suffix

128
yaml2dct.rb Executable file
View file

@ -0,0 +1,128 @@
#!/usr/bin/env ruby
require "yaml"
require "deepmergecore"
module DeepMerge
module DeepMergeHash
# ko_hash_merge! will merge and knockout elements prefixed with DEFAULT_FIELD_KNOCKOUT_PREFIX
def ko_deep_merge!(source, options = {})
default_opts = {:knockout_prefix => "--", :preserve_unmergeables => false}
DeepMerge::deep_merge!(source, self, default_opts.merge(options))
end
# deep_merge! will merge and overwrite any unmergeables in destination hash
def deep_merge!(source, options = {})
default_opts = {:preserve_unmergeables => false}
DeepMerge::deep_merge!(source, self, default_opts.merge(options))
end
# deep_merge will merge and skip any unmergeables in destination hash
def deep_merge(source, options = {})
default_opts = {:preserve_unmergeables => true}
DeepMerge::deep_merge!(source, self, default_opts.merge(options))
end
end # DeepMergeHashExt
end
class Hash
include DeepMerge::DeepMergeHash
end
# DCT PART
prefix=%{<?xml version="1.0" encoding="utf-8" ?>
<data-capture-requirements type="content" name="standard">
<ruleset name="standard">
<description>ylabeltable(Metapage)</description>
<item name="langue" pathid="langue">
<label>Entry Language</label>
<description>ylabelbold(The language in which the page is published)</description>
<database deploy-column="f"/>
<select required="t">
<inline command="/IW/iw-home/iw-perl/bin/iwperl /IW/iw-home/local/config/b2c_dev/inline/af_langue.ipl"/>
</select>
</item>
<!-- ######## START ######### -->}
suffix=%{
<!-- ######### END ########## -->
<script language="javascript" location="template-type" src="js/lockSelects.js"></script>
<script language="Javascript">// <![CDATA[
function collapseEverything() {
IWDatacapture.getItem("/content").setCollapsed(true);
}
$(document).ready(function() {
collapseEverything();
});
// ]]>
</script>
</ruleset>
</data-capture-requirements>
}
def boolDCT(name)
%{
<item name="#{name}" pathid="#{name}">
<label>#{name}</label>
<description></description>
<checkbox required="f">
<option value="#{name}" label="" selected="f"/>
</checkbox>
</item>}
end
def stringDCT(name)
%{
<item name="#{name}" pathid="#{name}">
<label>#{name}</label>
<description></description>
<text required="#{name}" size="80"/>
</item>}
end
def hashDCT(name,content)
%{
<container name="#{name}" pathid="#{name}">#{
content.gsub(/^/,' ')}
</container>}
end
def arrayDCT(name,content)
%{
<container name="#{name}" pathid="#{name}" min="0" max="65535">#{
content.gsub(/^/,' ')}
</container>}
end
def yamlObj2XML( obj, tab="" )
res=""
obj.each do |k,v|
case v
when TrueClass
res <<= boolDCT(k)
when String
res <<= stringDCT(k)
when Hash
content=yamlObj2XML(v,"#{tab} ")
res <<= hashDCT(k,content)
when Array
case v[0]
when Hash
merged={}
v.each do |h|
merged=merged.deep_merge(h)
end
content=yamlObj2XML(merged,"#{tab} ")
res <<= arrayDCT("#{k}", content)
else
yamlObj2XML(v,"#{tab} ")
end
else
puts "Else: #{v.class}"
end
end
return res
end
filename=ARGV[0]
puts prefix
puts yamlObj2XML(YAML::load_file(filename))
puts suffix