lib/dynamoid/fields/declare.rb
# frozen_string_literal: true
module Dynamoid
module Fields
# @private
class Declare
def initialize(source, name, type, options)
@source = source
@name = name.to_sym
@type = type
@options = options
end
def call
# Register new field metadata
@source.attributes = @source.attributes.merge(
@name => { type: @type }.merge(@options)
)
# Should be called before `define_attribute_methods` method because it
# defines an attribute getter itself
warn_about_method_overriding
# Dirty API
@source.define_attribute_method(@name)
# Generate getters and setters as well as other helper methods
generate_instance_methods
# If alias name specified - generate the same instance methods
if @options[:alias]
generate_instance_methods_for_alias
end
end
private
def warn_about_method_overriding
warn_if_method_exists(@name)
warn_if_method_exists("#{@name}=")
warn_if_method_exists("#{@name}?")
warn_if_method_exists("#{@name}_before_type_cast?")
end
def generate_instance_methods
# only local variable is visible in `module_eval` block
name = @name
@source.generated_methods.module_eval do
define_method(name) { read_attribute(name) }
define_method(:"#{name}?") do
value = read_attribute(name)
case value
when true then true
when false, nil then false
else
!value.nil?
end
end
define_method(:"#{name}=") { |value| write_attribute(name, value) }
define_method(:"#{name}_before_type_cast") { read_attribute_before_type_cast(name) }
end
end
def generate_instance_methods_for_alias
# only local variable is visible in `module_eval` block
name = @name
alias_name = @options[:alias].to_sym
@source.generated_methods.module_eval do
alias_method alias_name, name
alias_method :"#{alias_name}=", :"#{name}="
alias_method :"#{alias_name}?", :"#{name}?"
alias_method :"#{alias_name}_before_type_cast", :"#{name}_before_type_cast"
end
end
def warn_if_method_exists(method)
if @source.instance_methods.include?(method.to_sym)
Dynamoid.logger.warn("Method #{method} generated for the field #{@name} overrides already existing method")
end
end
end
end
end