Last active
December 18, 2015 11:09
-
-
Save tatat/5773417 to your computer and use it in GitHub Desktop.
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
require 'active_record' | |
module ActsAsSplittable | |
def acts_as_splittable(options = {}) | |
options.reverse_merge!( | |
callbacks: true, | |
) | |
extend ClassMethods | |
include InstanceMethods | |
if options[:callbacks] | |
after_initialize { new_record? or split_column_values! } | |
before_save { join_column_values! } | |
end | |
end | |
module ClassMethods | |
SPLITTABLE_DEFAULT_JOIN_PROCESS = Proc.new{|partials| partials.join } | |
def splittable_columns | |
@splittable_columns ||= {} | |
end | |
def splittable(column, options) | |
column = column.to_sym | |
partials = (options[:partials] || options[:pattern].names).map(&:to_sym) | |
splittable_columns[column] = [options[:pattern], partials, options[:on_split], options[:on_join] || SPLITTABLE_DEFAULT_JOIN_PROCESS] | |
partials.each do |partial| | |
define_method partial do | |
splittable_partials[partial] | |
end | |
define_method :"#{partial}=" do |value| | |
splittable_partials[partial] = value | |
end | |
end | |
end | |
def inherited(child) | |
super | |
child.splittable_columns.merge! splittable_columns.dup | |
end | |
end | |
module InstanceMethods | |
def split_column_values!(column = nil) | |
if column.nil? | |
self.class.splittable_columns.each_key{|key| send __method__, key } | |
else | |
column = column.to_sym | |
pattern, partials, on_split, on_join = self.class.splittable_columns[column] | |
value = send(column) | |
values = if on_split | |
on_split.is_a?(Symbol) ? | |
send(on_split, value) : on_split.(value) | |
elsif value | |
matches = value.match(pattern) | |
matches[1..(matches.length - 1)] | |
else | |
nil | |
end || [] | |
partials.each_with_index do |partial, index| | |
send :"#{partial}=", values[index] | |
end | |
end | |
self | |
end | |
def join_column_values!(column = nil) | |
if column.nil? | |
self.class.splittable_columns.each_key{|key| send __method__, key } | |
else | |
pattern, partials, on_split, on_join = self.class.splittable_columns[column.to_sym] | |
partials = partials.map{|partial| send(partial) } | |
send :"#{column}=", on_join.is_a?(Symbol) ? send(on_join, partials) : on_join.(partials) | |
end | |
self | |
end | |
def splittable_partials | |
@splittable_partials ||= {} | |
end | |
end | |
end | |
ActiveRecord::Base.extend ActsAsSplittable |
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
EMAIL_SPLIT_PATTERN = /^(?<email_local>[^@]+)@(?<email_domain>[^@]+)$/ | |
EMAIL_JOIN_PROCESS = Proc.new{|partials| partials.join('@') } | |
class Splittable < ActiveRecord::Base | |
acts_as_splittable | |
splittable :email, pattern: /^([^@]+)@([^@]+)$/, partials: [:email_local, :email_domain], on_join: EMAIL_JOIN_PROCESS | |
splittable :postal_code, pattern: /^(?<postal_code1>[0-9]{3})(?<postal_code2>[0-9]{4})$/ | |
splittable :phone_number, partials: [:phone_number1, :phone_number2, :phone_number3], on_split: :split_phone_number, on_join: :join_phone_number | |
protected | |
def split_phone_number(value) | |
return if value.nil? | |
matches = value.match(/^([0-9]{3})([0-9]{4})([0-9]{4})$/) | |
matches[1..(matches.length - 1)] | |
end | |
def join_phone_number(partials) | |
partials.join | |
end | |
end | |
class SplittableInherited < Splittable; end | |
class SplittableInheritedInherited < SplittableInherited; end | |
class SplittableWithValidation < ActiveRecord::Base | |
self.table_name = 'splittables' | |
acts_as_splittable | |
splittable :email, pattern: EMAIL_SPLIT_PATTERN, on_join: EMAIL_JOIN_PROCESS | |
validates :email_local, format: { with: /\A[a-zA-Z0-9_.-]+\Z/ } | |
validates :email_domain, format: { with: /\A(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,4}\Z/ } | |
end | |
class SplittableWithValidationForOriginalColumn < SplittableWithValidation | |
self.table_name = 'splittables' | |
acts_as_splittable | |
splittable :email, pattern: EMAIL_SPLIT_PATTERN, on_join: EMAIL_JOIN_PROCESS | |
validates :email, format: { with: /\A[a-zA-Z0-9_.-]+@(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,4}\Z/ } | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment