lib/ruote/exp/merge.rb in ruote-2.2.0 vs lib/ruote/exp/merge.rb in ruote-2.3.0
- old
+ new
@@ -1,7 +1,7 @@
#--
-# Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
+# Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
@@ -28,46 +28,107 @@
#
# Gathering methods for merging workitems.
#
module MergeMixin
+ # Given a list of workitems and a merge_type, will merge according to
+ # the merge type.
#
+ # The return value is the merged workitem.
+ #
+ def merge_workitems(workitems, merge_type)
+
+ workitems.inject(nil) do |t, wi|
+ merge_workitem(workitems.index(wi), t, wi, merge_type)
+ end
+ end
+
# Merge workitem 'source' into workitem 'target'.
#
# If type is 'override', the source will prevail and be returned.
#
- # If type is 'mix', the source fields will be merge into the target fields.
+ # If type is 'mix', the source fields will be merged into the target fields.
#
# If type is 'isolate', the source fields will be placed in a separte field
# in the target workitem. The name of this field is the child_id of the
# source workitem (a string from '0' to '99999' and beyond)
#
- def merge_workitems(index, target, source, type)
+ # The 'concat' type merges hashes and concats arrays. The 'union' type
+ # behaves much like 'concat', but it makes sure to remove duplicates.
+ #
+ # Warning: 'union' will remove duplicates that were present _before_ the
+ # merge.
+ #
+ def merge_workitem(index, target, source, merge_type)
- return source if type == 'override'
+ return source if merge_type == 'override'
if target == nil
- case type
+
+ case merge_type
+
+ #when 'mix'
+ # do nothing
+
+ when 'stack'
+ source['fields'] = { 'stack' => [ source['fields'] ] }
+
when 'isolate'
source['fields'] = { index.to_s => source['fields'] }
+
+ #when 'union', 'concat'
+ # do nothing
+ end
+
+ source
+
+ else
+
+ case merge_type
+
+ when 'mix'
+
+ target['fields'].merge!(source['fields'])
+
when 'stack'
- source['fields'] = { 'stack' => [ source['fields'] ] }
+
+ target['fields']['stack'] << source['fields']
+ target['fields']['stack_attributes'] = compile_atts
+
+ when 'isolate'
+
+ target['fields'][index.to_s] = source['fields']
+
+ when 'union', 'concat', 'deep'
+
+ source['fields'].each do |k, sv|
+
+ tv = target['fields'][k]
+
+ if sv.is_a?(Array) and tv.is_a?(Array)
+ tv.concat(sv)
+ tv.uniq! if merge_type == 'union'
+ elsif sv.is_a?(Hash) and tv.is_a?(Hash)
+ merge_type == 'deep' ? deep_merge!(tv, sv) : tv.merge!(sv)
+ else
+ target['fields'][k] = sv
+ end
+ end
end
+
+ target
end
+ end
- return source unless target
+ protected
- case type
- when 'mix'
- target['fields'].merge!(source['fields'])
- when 'stack'
- target['fields']['stack'] << source['fields']
- target['fields']['stack_attributes'] = expand_atts
- else # 'isolate'
- target['fields'][index.to_s] = source['fields']
- end
+ # Inspired by the one found in ActiveSupport, though not strictly equivalent.
+ #
+ def deep_merge!(target, source)
- target
+ target.merge!(source) do |k, o, n|
+ o.is_a?(Hash) && n.is_a?(Hash) ? deep_merge!(o, n) : n
+ end
end
end
end