هل من الممكن التحقق من عدد الأساليب المخصصة لـ Proc في Ruby؟

StackOverflow https://stackoverflow.com/questions/4299554

  •  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}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top