Last active
March 15, 2020 16:18
-
-
Save RichOrElse/da18acabc691d1176b8bc6896fd73cfd to your computer and use it in GitHub Desktop.
Functional Programming in Rails
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
# 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 |
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
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 |
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
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 |
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
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