-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
0 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1 @@ | ||
# frozen_string_literal: true | ||
|
||
require "attribute_helpers/version" | ||
|
||
# Provides helper functionality for ruby classes that store various | ||
# database-unfriendly types as instance variables. It automatically serializes | ||
# and deserializes things like classes and symbols to interact easily with both | ||
# the database and your application code. | ||
|
||
module AttributeHelpers | ||
def attr_symbol(*attrs) | ||
transform_attributes(*attrs, &:to_sym) | ||
end | ||
|
||
def attr_class(*attrs) | ||
transform_attributes(*attrs) { |val| Kernel.const_get(val) } | ||
end | ||
|
||
# Implementation Note | ||
# ------------------- | ||
# The transformers above all work by creating an anonymous module for each | ||
# group of attributes that gets prepended into the class the AttributeHelpers | ||
# module is included into. These modules need to be defined at method call | ||
# time to avoid leaking the overrided methods into other classes this module | ||
# is included in. | ||
# | ||
# This anonymous module needs to be prepended to work in ActiveRecord classes. | ||
# This is because ActiveRecord doesn't have accessors/mutators defined until | ||
# an instance is created, which means we need to use the prepend pattern | ||
# because attempts to use instance_method instance_method will not find the | ||
# method in the class context as it will not exist until it is dynamically | ||
# created when an instance is created. Prepend works for us because it inserts | ||
# the behavior *below* the class in the inheritance hierarchy, so we can | ||
# access the default ActiveRecord accessors/ mutators through the use of | ||
# super(). | ||
# | ||
# More information here: http://stackoverflow.com/a/4471202/1103543 | ||
def transform_attributes(*attrs) | ||
transformer = Module.new do | ||
attrs.each do |attr| | ||
# Overwrite the accessor. | ||
define_method(attr) do | ||
val = super() | ||
val && yield(val) | ||
end | ||
|
||
# Overwrite the mutator. | ||
define_method("#{attr}=") do |val| | ||
super(val&.to_s) | ||
end | ||
end | ||
end | ||
|
||
prepend transformer | ||
end | ||
end |