Initial commit
This commit is contained in:
commit
ad89dd5ccc
4 changed files with 457 additions and 0 deletions
210
deepmergecore.rb
Executable file
210
deepmergecore.rb
Executable 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
42
mustache2tpl.pl
Executable 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#&#&#g ; s#<#<#; s#>#>#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
77
yaml2dcr.rb
Executable 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('&','&').gsub('<','<').gsub('>','>')
|
||||
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
128
yaml2dct.rb
Executable 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
|
Loading…
Reference in a new issue