هل من الممكن التحقق من عدد الأساليب المخصصة لـ Proc في Ruby؟
-
29-09-2019 - |
سؤال
أنا أعمل حاليًا على DSL فيما يتعلق بالمحاسبة. ما أود أن أتمكن من فعله هو:
accountant do
credit @account_1, -@amount
debit @account_2, @amount
end
حاليا ، هذا ينفذ الطريقة التالية:
class Accountant
def accountant &block
AccountantHelper.class_eval(&block)
end
end
... والتي بدورها تنفذ الكتلة على فئة Accordanthelper ، واصفا أساليب "الائتمان" و "الخصم" على التوالي:
class AccountantHelper
def self.credit account, amount
account.credit amount
end
def self.debit account, amount
account.debit amount
end
end
(يرجى كبح أي نيران حول استخدام class_eval () - هذا مجرد نموذج أولي بعد كل شيء!)
الهدف من ذلك هو أن تكون الكتلة بمثابة معاملة ، مما يضمن أنه إذا لم يكن من الممكن تنفيذ الكتلة بأكملها بنجاح ، فلا ينبغي لأي منها. ومع ذلك ، بالإضافة إلى ذلك ، يجب أن يتحقق أيضًا من سلامة البيانات التي تم تمريرها في الكتلة. في هذه الحالة ، أحتاج إلى التحقق من أن هناك طريقة "ائتمان" و "خصم" داخل الكتلة (في محاسبة الدقة المزدوجة ، يجب أن يكون هناك أيضًا على الأقل خصم واحد على الأقل ، والعكس صحيح). حاليا يمكنني الاتصال:
accountant do
credit @account_1, @amount
end
... وسيتم تنفيذ الكود دون أي أخطاء. سيكون هذا أمرًا سيئًا لأنه لا يوجد "خصم" مقابل للحفاظ على الحسابات في توازن.
هل من الممكن التحقق من ما يتم تمريره في الكتلة؟ أم أنا أتجه إلى المسار الخطأ هنا؟
المحلول
أعتقد أنه يمكنك جعل الخاص بك credit
و debit
الإجراءات "كسول" ، بحيث يتم تنفيذها بواسطة طريقة الغلاف ، بعد التحقق من الصحة. إليك دليل على المفهوم ، على غرارك ، ولكن بدون جزء metaprogramming ، تخطي للتوضيح:
def transaction
yield
if @actions.map(&:last).inject(&:+) == 0
@actions.each do |account, amount|
@accounts[account] += amount
end
@actions = []
puts 'transaction executed ok'
else
puts 'balance not zero, rolling back transaction'
# rollback (effectively, do nothing)
end
end
def credit account, amount
@actions << [account, amount]
end
def debit account, amount
@actions<< [account, -amount]
end
@actions = []
@accounts = {a: 0, b: 0, c: 0} # start with three blank accounts
transaction do
credit :a, 5
debit :b, 2
debit :c, 3
end
#=>transaction executed ok
p @accounts
#=>{:a=>5, :b=>-2, :c=>-3}
transaction do
credit :a, 5
debit :b, 4
end
#=> balance not zero, rolling back transaction
p @accounts
#=> {:a=>5, :b=>-2, :c=>-3}