Skip to content

Instantly share code, notes, and snippets.

@eljojo
Created December 8, 2015 19:41
Show Gist options
  • Save eljojo/3682cdbde11f49d6a545 to your computer and use it in GitHub Desktop.
Save eljojo/3682cdbde11f49d6a545 to your computer and use it in GitHub Desktop.
some playing with functional programming and ruby
# A HashManipulation is a helper object.
# The idea is to aid when modifying hashes.
# changes = HashManipulation.new
# changes.key { |key| key.upcase }
# changes.value { |value| value.length }
# changes.("children" => [1, 2, 3]) # {"CHILDREN" => 3}
module Reports
class HashManipulation
def initialize
@key = -> (obj) { obj }
@value = -> (obj) { obj }
end
def key(&block)
@key = block
self
end
def value(&block)
@value = block
self
end
def call(obj)
obj.map do |key, value|
[@key.call(key), @value.call(value)]
end.to_h
end
def self.value(&block)
self.new.value(&block)
end
def self.key(&block)
self.new.key(&block)
end
end
end
# A Pipe is intended to be simple way of doing function composition (?)
module Reports
class Pipe
def initialize(procs = [])
@procs = procs
end
delegate :<<, to: :@procs
def call(obj)
@procs.inject(obj) { |memo, func| func.(memo) }
end
end
end
module Reports
class RepeatSwitches
def initialize
@contract_data = ContractDatum.all.ordered.includes(:user)
end
def report
group_by_first_or_second_switch = procerize(:group_by) do |contract|
first_switch?(contract) ? "First Switch" : "Repeat Switch"
end
get_counts = HashManipulation.value {|values| values.length }
get_switches_count = HashManipulation.value do |contracts|
get_counts.(group_by_first_or_second_switch.(contracts))
end
add_totals = HashManipulation.value do |hash|
hash.dup.tap do |res|
res["Total"] = hash.values.inject(:+)
end
end
pipe = Pipe.new
pipe << get_switches_count
pipe << add_totals
final_function = group_by_month(pipe)
final_function.(@contract_data)
end
def group_by_month(action)
group_by_month = procerize(:group_by) do |contract_datum|
ordered_at = contract_datum.ordered_at
[ordered_at.year, ordered_at.mon]
end
sort_by_first = -> (hash) { hash.sort_by(&:first).to_h }
humanize_month = HashManipulation.key{|(year, month)| "#{year}/#{month}" }
pipe = Pipe.new
pipe << group_by_month
pipe << action
pipe << sort_by_first
pipe << humanize_month
pipe
end
private
def first_switch?(contract_datum)
ordered_at = ContractDatum.arel_table[:ordered_at]
user_contracts = contract_datum.user.contract_data.ordered
user_contracts.where(ordered_at.lt(contract_datum.ordered_at)).empty?
end
def procerize(method, &block)
-> (obj) { obj.send(method, &block) }
end
end
end
@eljojo
Copy link
Author

eljojo commented Dec 8, 2015

@plexus hey this is super cool! Thanks a lot for your help!
I think I finally found a good example (for myself) so I can practice some functional programming.

thanks for the motivation as well :)

@bitboxer
Copy link

bitboxer commented Dec 8, 2015

@plexus was faster and way more insightfull than I would have been 👍 .

@eljojo
Copy link
Author

eljojo commented Dec 9, 2015

@bitboxer the intention still counts :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment