Skip to content

Instantly share code, notes, and snippets.

@udzura
Last active December 10, 2015 03:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save udzura/4376997 to your computer and use it in GitHub Desktop.
Save udzura/4376997 to your computer and use it in GitHub Desktop.
ディースィーアイかと思ったらなんだか変なことになった思考実験.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
Copy link
Author

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