Created
February 12, 2014 20:15
-
-
Save pricees/8963659 to your computer and use it in GitHub Desktop.
Extending an Array/ActiveRelation vs Subclassing Array
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
names = %w[SK Steve Pedro Anthony Milo Xiping] | |
Person = Struct.new :name | |
module Helloable | |
def hello_all_the_names | |
each { |person| puts "Helloable | Hello #{person.name}" } | |
end | |
end | |
# An interesting way to add functionality to an array is to extend it | |
ary = names.map { |name| Person.new name } | |
ary.extend(Helloable) | |
ary.hello_all_the_names | |
# Prints: | |
# Helloable | Hello SK | |
# Helloable | Hello Steve | |
# Helloable | Hello Pedro | |
# Helloable | Hello Anthony | |
# Helloable | Hello Milo | |
# Helloable | Hello Xiping | |
# My preference would be to subclass an array, it costs less | |
class HelloArray < Array | |
def hello_all_the_names | |
each { |person| puts "HelloArray | Hello #{person.name}" } | |
end | |
end | |
hello_ary = HelloArray.new(names.map { |name| Person.new name }) | |
hello_ary.hello_all_the_names | |
# Prints: | |
# HelloArray | Hello SK | |
# HelloArray | Hello Steve | |
# HelloArray | Hello Pedro | |
# HelloArray | Hello Anthony | |
# HelloArray | Hello Milo | |
# HelloArray | Hello Xiping | |
# Whats the point? | |
# | |
# Well we have code here | |
# | |
# | |
# | |
# /app/models/transaction.rb | |
# | |
class Transaction < ActiveRecord::Base | |
# | |
# [...] | |
# | |
module Balances | |
def sold | |
map{ |tx| tx.sold_amount }.sum | |
end | |
def sold_pending | |
map{ |tx| tx.sold_pending_amount }.sum | |
end | |
def sold_available | |
map{ |tx| tx.sold_available_amount }.sum | |
end | |
def payments | |
map{ |tx| tx.payments_amount }.sum | |
end | |
def payments_requested | |
map{ |tx| tx.payments_requested_amount }.sum | |
end | |
def payments_paid | |
map{ |tx| tx.payments_paid }.sum | |
end | |
def balance | |
sold - payments_requested - payments_paid | |
end | |
def available_balance | |
sold_available - payments_requested - payments_paid | |
end | |
def real_time_balance(id) | |
select { |tx| tx.id <= id && tx.count_in_total? }.map(&:amount_with_sign).sum | |
end | |
end | |
end | |
# Which are used to extend ActiveRelations | |
#app/controllers/user_transactions_finder.rb: @transactions.extend Transaction::Balances | |
#app/models/line_item_decorator.rb: include Transaction::Balances | |
#app/models/payment_transaction.rb: transactions.extend Transaction::Balances | |
# | |
# Extending an instance over and over wastes clock cycles. | |
# If we choose to make Balances an array subclass we can used it like so: | |
class Transaction < ActiveRecord::Base | |
module Balances < Array | |
end | |
end | |
transactions = Transaction::Balances.new transactions | |
@transactions = Transaction::Balances.new @transactions | |
# Now we do include it in a relationship in line item decorator. | |
# This might justify keep the balances in module form, however I might then | |
# decide to make: | |
# | |
# class BalancesArray < Array | |
# include Transaction:Balances | |
# end | |
# | |
# Either way, I think extending instances probably more of an anti-pattern that | |
# we should avoid. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This looks really good; I like the direction of the discussion. The use of
extend
orinclude
is a subtle, hidden way of implementing inheritance, even if it's only on a single instance. Back in GOF days, the maxim of the day was "prefer composition over inheritance", as that leads to small, focused objects that perform a small subset of functionality, and can be assembled in innovative ways.An even better argument is how cryptic the
Transaction::Balances
functionality has become. I had originally implemented the idea, and I don't recall why I choseextended
overBalance.new(array)
.