summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMichael Herold <opensource@michaeljherold.com>2018-08-11 10:50:17 -0500
committerMichael Herold <opensource@michaeljherold.com>2018-08-11 11:27:12 -0500
commit50898af55a4fd9fac96e5748e59abee3614e786b (patch)
tree97a8250aa0bfdbc239719a1e92b2f2c467d101cc /lib
parent6ab1e45ef74526fe983b4ed29174b781db00cd24 (diff)
downloadhashie-50898af55a4fd9fac96e5748e59abee3614e786b.tar.gz
Refactor PropertyTranslation for readability
The original implementation of PropertyTranslation was heavily reliant longer methods that added a lot of cognitive load for understanding what should be happening at any given point. This refactor gives names for all of the steps that happen at each step to make it easier to reason about bugs and additions.
Diffstat (limited to 'lib')
-rw-r--r--lib/hashie/extensions/dash/property_translation.rb72
1 files changed, 48 insertions, 24 deletions
diff --git a/lib/hashie/extensions/dash/property_translation.rb b/lib/hashie/extensions/dash/property_translation.rb
index 2d28080..25b6499 100644
--- a/lib/hashie/extensions/dash/property_translation.rb
+++ b/lib/hashie/extensions/dash/property_translation.rb
@@ -40,7 +40,7 @@ module Hashie
module PropertyTranslation
def self.included(base)
base.instance_variable_set(:@transforms, {})
- base.instance_variable_set(:@translations_hash, {})
+ base.instance_variable_set(:@translations_hash, ::Hash.new { |hash, key| hash[key] = {} })
base.extend(ClassMethods)
base.send(:include, InstanceMethods)
end
@@ -72,21 +72,16 @@ module Hashie
def property(property_name, options = {})
super
- if options[:from]
- if property_name == options[:from]
- raise ArgumentError, "Property name (#{property_name}) and :from option must not be the same"
- end
-
- translations_hash[options[:from]] ||= {}
- translations_hash[options[:from]][property_name] = options[:with] || options[:transform_with]
+ from = options[:from]
+ converter = options[:with]
+ transformer = options[:transform_with]
- define_method "#{options[:from]}=" do |val|
- self.class.translations_hash[options[:from]].each do |name, with|
- self[name] = with.respond_to?(:call) ? with.call(val) : val
- end
- end
- elsif options[:transform_with].respond_to? :call
- transforms[property_name] = options[:transform_with]
+ if from
+ fail_self_transformation_error!(property_name) if property_name == from
+ define_translation(from, property_name, converter || transformer)
+ define_writer_for_source_property(from)
+ elsif valid_transformer?(transformer)
+ transforms[property_name] = transformer
end
end
@@ -103,26 +98,49 @@ module Hashie
end
def translations
- @translations ||= {}.tap do |h|
+ @translations ||= {}.tap do |translations|
translations_hash.each do |(property_name, property_translations)|
- h[property_name] = if property_translations.size > 1
- property_translations.keys
- else
- property_translations.keys.first
- end
+ translations[property_name] =
+ if property_translations.size > 1
+ property_translations.keys
+ else
+ property_translations.keys.first
+ end
end
end
end
def inverse_translations
- @inverse_translations ||= {}.tap do |h|
+ @inverse_translations ||= {}.tap do |translations|
translations_hash.each do |(property_name, property_translations)|
- property_translations.each_key do |k|
- h[k] = property_name
+ property_translations.each_key do |key|
+ translations[key] = property_name
end
end
end
end
+
+ private
+
+ def define_translation(from, property_name, translator)
+ translations_hash[from][property_name] = translator
+ end
+
+ def define_writer_for_source_property(property)
+ define_method "#{property}=" do |val|
+ __translations[property].each do |name, with|
+ self[name] = with.respond_to?(:call) ? with.call(val) : val
+ end
+ end
+ end
+
+ def fail_self_transformation_error!(property_name)
+ raise ArgumentError, "Property name (#{property_name}) and :from option must not be the same"
+ end
+
+ def valid_transformer?(transformer)
+ transformer.respond_to? :call
+ end
end
module InstanceMethods
@@ -156,6 +174,12 @@ module Hashie
fail_no_property_error!(property) unless self.class.property?(property)
true
end
+
+ private
+
+ def __translations
+ self.class.translations_hash
+ end
end
end
end