Skip to content

Instantly share code, notes, and snippets.

@udzura

udzura/concerned_domain.rb

Last active Dec 10, 2015
Embed
What would you like to do?
ディースィーアイかと思ったらなんだか変なことになった思考実験.rb
# ConcernedDomain モジュール
# 特定のActiveRecordなどのモデルについて、特定の関心事のみを行なうためのラッパークラス
# その他のことは原則しない前提で
# 関心事をまたいだ処理もできるが、そうするとなんと!コードが自動的に汚くなってくれて便利です
#
module ConcernedDomain
extend ActiveSupport::Concern
included do
def initialize(model)
@model = model
end
parent, concern_name = name.split '::'
define_method(parent.downcase) { @model }
# force pre-load attributish instance methods for ActiveFxckingRecord
parent.constantize.first if parent.constantize.respond_to? :first
delegate *(parent.constantize.instance_methods - [:object_id, :__send__, :class, :is_a?, :inspect, :display]), to: parent.downcase
# introduce concern changing method
parent.constantize.class_eval do
define_method("as_" + concern_name.underscore) do
self.class.const_get(concern_name).new(self)
end
end
end
end
class User < AR::Base
# has an attribute of `money: integer'
has_many :purchases
end
class User::Customer
include ConcernedDomain
def purchase(item)
if purchasable?(item)
purchases.create(item: item)
end
end
def purchasable?(item)
money >= item.price
end
# Across the concern universe
def debug_buy!
# `user.as_admin' looks weird, but can do it
if user.as_admin.has_role?(:ec_admin)
purchases.create(item: item)
end
end
end
# Use it!
@user = User.find($id).as_customer
@user.purchase(Item.find($params))
if @user.purchases.empty?
@user.debug_buy!(Item.find($params))
end
@udzura

This comment has been minimized.

Copy link
Owner Author

@udzura udzura commented Dec 26, 2012

制限事項:
as_* メソッドのデリゲーションが、定義の順番に依存する……
ので、たぶん method_missing でフックした上でキャッシュとしてメソッド定義する方がきれい(ARの属性メソッドの委譲もへんてこだし)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.