lib/snake-eyes/interface_changes.rb in snake-eyes-0.0.8 vs lib/snake-eyes/interface_changes.rb in snake-eyes-0.1.0
- old
+ new
@@ -1,94 +1,51 @@
module SnakeEyes
module InterfaceChanges
+ KEYS_ALWAYS_PRESENT = [
+ "controller",
+ "action"
+ ]
+
def params(options = {})
validate_options(options)
original_params = super()
- return original_params unless original_params.any?
+ params_present = (original_params.keys | KEYS_ALWAYS_PRESENT).length > KEYS_ALWAYS_PRESENT.length
- # List of subtrees maintained to mark the depth-first traversal's position
- # throughout the transformation of the original param's keys, whereby the
- # last element is the traversal's current position and backtracking (going
- # from child to parent) is achieved by popping off the last element.
+ unless params_present
+ return original_params
+ end
- original_params_sub_trees = [
- original_params
- ]
-
- # Convert the relatively flat format used to specify the nested attributes
- # (easier for specification) into a series of nested objects (easier for
- # look-ups)
-
- nested_schema = build_nested_schema(options[:nested_attributes] || {})
-
@previous_params ||= { }
- return @previous_params[nested_schema] if @previous_params[nested_schema]
-
- # Similar to original_params_sub_trees, a list of subtrees used to maintain
- # the traversal position of nested_schema. This is kept in sync with the
- # traversal of original_params, to ensure the correct leaf of
- # nested_schema is checked at each point in the traversal of original_params
-
- nested_schema_sub_trees = [
- nested_schema
- ]
-
- transformed_params = original_params.deep_transform_keys do |original_key|
- # Synchronise the original params sub-tree with the current key being
- # transformed. We can detect that the sub-tree is stale because the key
- # being transformed does not appear amongst its own. When the sub-tree is
- # indeed stale, move the position to its parent for the original params
- # sub-tree and the nested schema sub-tree and repeat the check.
-
- while original_params_sub_trees.length > 1 && original_params_sub_trees.last[original_key].nil?
- original_params_sub_trees.pop
- nested_schema_sub_trees.pop
+ nested_schema = build_options_schema(options[:nested_attributes] || {}, '') do |target, parent_name|
+ if parent_name.empty? || parent_name.starts_with?('_')
+ target
+ else
+ target.merge({ _attributes_suffix: true })
end
+ end
- original_params_sub_tree = original_params_sub_trees.last[original_key]
+ options[:nested_attributes] = nested_schema
- # Append the '_attributes' suffix if the original params key has the
- # same name and is nested in the same place as one mentioned in the
- # nested_attributes option
+ return @previous_params[options] if @previous_params[options]
- transformed_key_base = original_key.underscore
+ transformed_params = deep_transform(original_params, options)
- transformed_key =
- if nested_schema_sub_trees.last[transformed_key_base]
- transformed_key_base + '_attributes'
- else
- transformed_key_base
- end
+ @previous_params[options] = @snake_eyes_params = ActionController::Parameters.new(transformed_params)
- if original_params_sub_tree.kind_of?(Hash)
- original_params_sub_trees.push(original_params_sub_tree)
-
- nested_schema_sub_trees.push(
- nested_schema_sub_trees.last[transformed_key_base] ||
- nested_schema_sub_trees.last['_' + transformed_key_base] ||
- {}
- )
- end
-
- transformed_key
- end
-
- @previous_params[nested_schema] = @snake_eyes_params = ActionController::Parameters.new(transformed_params)
-
log_snakized_params
@snake_eyes_params
end
private
def validate_options(options)
options.keys.each do |key|
- raise ArgumentError.new("SnakeEyes: params received unrecognised option '#{key}'") if key != :nested_attributes
+ raise ArgumentError.new("SnakeEyes: params received unrecognised option '#{key}'") if key != :nested_attributes && key != :substitutions
end
end
def log_snakized_params
if SnakeEyes.log_snake_eyes_parameters
@@ -98,30 +55,119 @@
logger.info " SnakeEyes Parameters: #{filtered_params.inspect}"
end
end
- def build_nested_schema(attributes_list = [])
+ def deep_transform(target, options = {})
- if attributes_list.kind_of?(Array)
+ nested_attributes = options[:nested_attributes] || {}
- attributes_list.inject({}) do |memo, nested_attribute|
- memo.merge(build_nested_schema(nested_attribute))
+ substitutions =
+ if options[:substitutions].kind_of?(Array)
+ options[:substitutions].map(&:stringify_keys)
+ else
+ (options[:substitutions] || {}).stringify_keys
+ end
+
+ if target.kind_of?(Array)
+ target.map do |targetElement|
+ deep_transform(targetElement, {
+ nested_attributes: nested_attributes['*'],
+ substitutions: substitutions.kind_of?(Array) ? {} : substitutions['*']
+ })
end
- elsif attributes_list.kind_of?(Hash)
+ elsif target.kind_of?(Hash)
- attributes_list.inject({}) do |memo, key_and_value|
+ target.inject({}) do |memo, key_and_value|
key, value = key_and_value
- memo[key.to_s] = build_nested_schema(value)
+
+ # Append the '_attributes' suffix if the original params key has the
+ # same name and is nested in the same place as one mentioned in the
+ # nested_attributes option
+
+ transformed_key_base = key.to_s.underscore
+
+ transformed_key =
+ if nested_attributes[transformed_key_base] && nested_attributes[transformed_key_base][:_attributes_suffix]
+ transformed_key_base + '_attributes'
+ else
+ transformed_key_base
+ end
+
+ transformed_value = deep_transform(value,
+ {
+ nested_attributes: nested_attributes[transformed_key_base] || nested_attributes['_' + transformed_key_base],
+ substitutions: substitutions.kind_of?(Array) ? {} : substitutions[transformed_key_base]
+ }
+ )
+
+ memo[transformed_key] = transformed_value
+
memo
end
else
+ perform_substitution(target, substitutions)
+ end
- { attributes_list.to_s.underscore => {} }
+ end
+ def perform_substitution(target, substitution)
+ if substitution.kind_of?(Array)
+ matching_substitution = substitution.find do |substitution_item|
+ has_substitution_keys?(substitution_item) && target === substitution_item["replace"]
+ end
+
+ if matching_substitution
+ matching_substitution["with"]
+ else
+ target
+ end
+
+ else
+ if has_substitution_keys?(substitution)
+ target === substitution["replace"] ? substitution["with"] : target
+ else
+ target
+ end
end
+ end
+ def has_substitution_keys?(substitution)
+ substitution.has_key?("replace") && substitution.has_key?("with")
end
+
+ def build_options_schema(attributes_list = [], parent_name = '', options = {}, &block)
+
+ if attributes_list.kind_of?(Array)
+ attributes_array = attributes_list.inject({}) do |memo, nested_attribute|
+ memo.merge(build_options_schema(nested_attribute, parent_name, options, &block))
+ end
+
+ yield(attributes_array, parent_name)
+
+ elsif attributes_list.kind_of?(Hash) && (!options[:internal_attributes] || (attributes_list.keys & options[:internal_attributes]).length > options[:internal_attributes].length)
+
+ attributes_hash = attributes_list.inject({}) do |memo, key_and_value|
+ key, value = key_and_value
+
+ memo[key.to_s] = yield(build_options_schema(value, '', options, &block), key.to_s)
+
+ memo
+ end
+
+ yield(attributes_hash, parent_name)
+ else
+
+ {
+ attributes_list.to_s.underscore => yield({}, attributes_list.to_s.underscore)
+ }
+
+ end
+
+ end
+
+
end
+
end