Skip to content

Instantly share code, notes, and snippets.

@RichOrElse
Last active March 15, 2020 16:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RichOrElse/da18acabc691d1176b8bc6896fd73cfd to your computer and use it in GitHub Desktop.
Save RichOrElse/da18acabc691d1176b8bc6896fd73cfd to your computer and use it in GitHub Desktop.
Functional Programming in Rails
# turns methods into functions
class FunctionFor < Module
def initialize(*method_names)
@method_names = method_names.each { |named| override named }
end
def override(named)
define_method(named) do |*input, &block|
return function_for[named] if input.none? && block.nil?
super(*input, &block)
end
end
def prepended(base)
return if base.method_defined? :function_for
base.define_method(:function_for) do
@function_for ||= Hash.new do |cached, name|
cached[name] = method(name).super_method
end
end
end
def included(base)
raise 'Please use prepend'
end
def inspect
"#{self.class.name}[%s]" % @method_names.join(' ')
end
class << self
alias_method :[], :new
end
end
module Query
class ByCompany
attr_reader :company, :by_company
alias_method :all, :by_company
delegate :to_sql, to: :all
def initialize(company, relation)
@company = company
@by_company = relation.not_deleted.where(company: company)
end
def in_company_timezone(time)
return if time.blank?
DateTime.parse(time).in_time_zone(company.timezone)
end
def format_date(time)
return if time.blank?
in_company_timezone(time).to_date.iso8601
end
def format_time(time)
return if time.blank?
in_company_timezone(time).strftime('%H:%M')
end
prepend FunctionFor[:format_time, :format_date]
def name_job_status
@name_job_status ||= JobStatus.where(company: company).pluck(:id, :name).to_h
end
def name_job_priority
@name_job_priority ||= Priority.pluck(:id, :name).to_h
end
class << self
alias_method :[], :new
end
end
end
class Query::ByJobs < Query::ByCompany
def initiaze(company, jobs = Job.all)
super
end
def all
jobs = by_company
end
def mapping_from(data)
{
start_date: data[:start_at],
start_time: data[:start_at],
}
end
def formatting
@formatting ||= {
start_time: time_format,
start_date: date_format,
}
end
end
module Query
module Formatting
def self::Type(type)
return '' if type.blank?
type.split('::').last
end
def self::Money(value)
return BigDecimal(0) if value.blank?
BigDecimal(value, 2)
end
HUMANIZE_TYPE = method(:Type)
FORMAT_MONEY = method(:Money)
YES_OR_NO = Hash.new('Yes').merge!(true => 'Yes', false => 'No', nil => 'No').freeze
def before_formatting(data)
{}
end
def formatting
@formatting ||= {}
end
def after_formatting(data)
{}
end
def merge_before_formatting(data)
data.merge! before_formatting(data)
end
def merge_formatting(data)
data.merge!(formatting) do |key, value, format|
format[value]
end
end
def merge_after_formatting(data)
data.merge! after_formatting(data)
end
prepend FunctionFor[:merge_before_formatting, :merge_formatting, :merge_after_formatting]
delegate :connection, to: ActiveRecord::Base
include Enumerable
if Rails.env.test?
MARK_MISSING_COLUMNS = Hash.new { |_, missing_column| "<#{missing_column}>" }
.method(:merge).to_proc
else
MARK_MISSING_COLUMNS = nil
end
def each(&blk)
connection.execute(to_sql)
.map(&:symbolize_keys)
.each(&merge_before_formatting)
.each(&merge_formatting)
.each(&merge_after_formatting)
.map(&:stringify_keys)
.map(&MARK_MISSING_COLUMNS)
.each(&blk)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment