রুবিতে পদ্ধতি যুক্তিগুলি অ্যাক্সেস করার কোনও উপায় আছে কি?


102

রুবি এবং আরওআর-এর জন্য নতুন এবং এটি প্রতিদিন ভালবাসা, সুতরাং এটি আমার প্রশ্ন যেহেতু এটি কীভাবে গুগল করবেন আমি ধারণা রাখি না (এবং আমি চেষ্টা করেছি :))

আমাদের পদ্ধতি আছে

def foo(first_name, last_name, age, sex, is_plumber)
    # some code
    # error happens here
    logger.error "Method has failed, here are all method arguments #{SOMETHING}"    
end

সুতরাং আমি প্রতিটি যুক্তি না দিয়েই সমস্ত যুক্তি পদ্ধতিতে পাস করার উপায়টি কীভাবে সন্ধান করছি। যেহেতু এটি রুবি, আমি ধরে নিই যে একটি উপায় আছে :) এটি যদি জাভা হত তবে আমি কেবল তাদের তালিকা করতাম :)

আউটপুট হবে:

Method has failed, here are all method arguments {"Mario", "Super", 40, true, true}

1
রেহ ক্রলজ স্বেগামী!
পিপীলিকা

1
আমি মনে করি যে সমস্ত উত্তরগুলির মধ্যে এটি উল্লেখ করা উচিত যে "কিছু কোড" যদি আর্গুমেন্ট আবিষ্কারের পদ্ধতিটি চালুর আগে আর্গুমেন্টের মান পরিবর্তন করে তবে এটি নতুন মানগুলি দেখায়, যে মানগুলি পাস হয়েছিল তা নয়, সুতরাং আপনার তাদের সঠিকভাবে ধরে নেওয়া উচিত নিশ্চিত হতে দূরে। এটি বলেছিল, এর জন্য আমার প্রিয় ওয়ান-লাইনার (পূর্ববর্তী উত্তরগুলি দেওয়া ক্রেডিট সহ):method(__method__).parameters.map { |_, v| [v, binding.local_variable_get(v)] }
ব্রায়ান ডিটারলিং

উত্তর:


159

রুবি ১.৯.২ এ এবং পরে আপনি সেই parametersপদ্ধতির পরামিতিগুলির তালিকা পেতে কোনও পদ্ধতিতে পদ্ধতিটি ব্যবহার করতে পারেন । এটি প্যারামিটারের নাম এবং এটি প্রয়োজনীয় কিনা তা নির্দেশ করে এমন জোড়ার একটি তালিকা ফিরিয়ে দেবে।

যেমন

যদি তুমি করো

def foo(x, y)
end

তারপর

method(:foo).parameters # => [[:req, :x], [:req, :y]]

আপনি __method__বর্তমান পদ্ধতির নাম পেতে বিশেষ পরিবর্তনশীলটি ব্যবহার করতে পারেন । সুতরাং একটি পদ্ধতির মধ্যে এর পরামিতিগুলির নামগুলি মাধ্যমে পাওয়া যায়

args = method(__method__).parameters.map { |arg| arg[1].to_s }

তারপরে আপনি প্রতিটি প্যারামিটারের নাম এবং মানটি প্রদর্শন করতে পারেন

logger.error "Method failed with " + args.map { |arg| "#{arg} = #{eval arg}" }.join(', ')

দ্রষ্টব্য: যেহেতু এই উত্তরটি মূলত রচনা করা হয়েছিল, রুবির বর্তমান সংস্করণগুলিতে evalপ্রতীক নিয়ে আর বলা যাবে না। এটির সমাধানের to_sজন্য, প্যারামিটারের নামগুলির তালিকা তৈরি করার সময় একটি স্পষ্ট যুক্ত করা হয়েছেparameters.map { |arg| arg[1].to_s }


4
এটি বোঝার জন্য আমার কিছুটা সময় প্রয়োজন :) :)
হারিস ক্রাজিনা

3
আমাকে
জানুন

3
+1 এটি সত্যিই দুর্দান্ত এবং মার্জিত; অবশ্যই সেরা উত্তর।
অ্যান্ড্রু মার্শাল

5
আমি রুবি ১.৯.৩ দিয়ে চেষ্টা করেছি, এবং এটির কাজ পেতে আপনাকে # {eval arg.to_s do করতে হবে, অন্যথায় আপনি একটি
টাইপ-এরর পান: সিম্বলটিকে স্ট্রিংয়ে

5
এদিকে, আরও ভাল হয়েছে এবং আমার দক্ষতা অর্জন করুন এবং এখন এই কোডটি বুঝতে পারেন।
হারিস ক্রাজিনা

55

রুবি ২.১ যেহেতু পদ্ধতি প্যারামিটারগুলি (আর্গুমেন্টগুলি) সহ যে কোনও স্থানীয় ভেরিয়েবলের মান পড়তে আপনি ਬਾਈ্যান্ডিং.লোকাল_ভেরিয়েবল_জেট ব্যবহার করতে পারেন । ধন্যবাদ যে আপনি এড়াতে গ্রহণযোগ্য উত্তরটি উন্নত করতে পারেনমন্দ Eval।

def foo(x, y)
  method(__method__).parameters.map do |_, name|
    binding.local_variable_get(name)
  end
end

foo(1, 2)  # => 1, 2

2.1 প্রথমতম হয়?
উছুগাকা

@ মুচুগাকা হ্যাঁ, এই পদ্ধতিটি <2.1 তে পাওয়া যায় না।
জাকুব জিরুতকা

ধন্যবাদ। এটি এটিকে সুন্দর করে তোলে: logger.info পদ্ধতি __ + "# # {args.inspect}" পদ্ধতি ( _ধর্মী )। পরিমিতি.ম্যাপ করুন | , নাম | logger.info "# {নাম} =" + বাইন্ডিং.লোকাল_ভরিয়াল_জেট (নাম) শেষ
মার্টিন ক্লিভার

এই পথেই যেতে হবে।
আরদী আরম

1
সম্ভাব্যরূপে দরকারী - যুক্তিটিকে একটি নামযুক্ত হ্যাশে রূপান্তর করা:Hash[method(__method__).parameters.map.collect { |_, name| [name, binding.local_variable_get(name)] }]
শেবা

19

এটি পরিচালনা করার একটি উপায়:

def foo(*args)
    first_name, last_name, age, sex, is_plumber = *args
    # some code
    # error happens here
    logger.error "Method has failed, here are all method arguments #{args.inspect}"    
end

2
কাজ করা এবং এর চেয়ে ভাল উত্তর না হলে গ্রহণযোগ্য হিসাবে ভোট দেওয়া হবে, এটির সাথে আমার একমাত্র সমস্যা হ'ল আমি পদ্ধতির স্বাক্ষর হারাতে চাই না, কিছু সেখানে রয়েছে ইন্টেলি বোধ এবং আমি এটি হারাতে ঘৃণা করব।
হারিস ক্রাজিনা

7

এটা একটি মজার প্রশ্ন। সম্ভবত স্থানীয়_ভরিভেবল ব্যবহার করছেন ? তবে ইওল ব্যবহার ব্যতীত অন্য কোনও উপায় থাকতে হবে। আমি কার্নেল ডকটিতে খুঁজছি

class Test
  def method(first, last)
    local_variables.each do |var|
      puts eval var.to_s
    end
  end
end

Test.new().method("aaa", 1) # outputs "aaa", 1

এটি এত খারাপ নয়, কেন এই অশুভ সমাধান?
হারিস ক্রাজিনা

এই ক্ষেত্রে এটি খারাপ নয় - ইভাল () ব্যবহার করা কখনও কখনও সুরক্ষা গর্ত হতে পারে। কেবলমাত্র আমি মনে করি এর থেকে আরও ভাল উপায় থাকতে পারে :) তবে আমি স্বীকার করি গুগল এই ক্ষেত্রে আমাদের বন্ধু নন
রাফায়েল

আমি এটি নিয়ে যাচ্ছি, খারাপ দিকটি হ'ল আপনি কোনও সহায়ক (মডিউল) তৈরি করতে পারবেন না যা এটির যত্ন নেবে, যেহেতু এটি আসল পদ্ধতিটি ছাড়ার সাথে সাথে এটি স্থানীয় যুদ্ধের বিভাজনগুলি করতে পারে না। তথ্যের জন্য সমস্ত ধন্যবাদ।
হারিস ক্রাজিনা

এটি আমাকে "TypeError দেয়: সিম্বলটিকে স্ট্রিংতে রূপান্তর করতে পারে না" যদি না আমি এটিকে পরিবর্তন করি eval var.to_s। এছাড়াও, এর একটি সতর্কতা হ'ল আপনি যদি এই লুপটি চালানোর আগে কোনও স্থানীয় ভেরিয়েবলগুলি সংজ্ঞায়িত করেন তবে সেগুলি পরামিতিগুলির পরামিতিগুলির সাথে যুক্ত করা হবে।
অ্যান্ড্রু মার্শাল

6
এটি সর্বাধিক মার্জিত এবং সুরক্ষিত পদ্ধতির নয় - আপনি যদি আপনার পদ্ধতির অভ্যন্তরে স্থানীয় ভেরিয়েবলটি সংজ্ঞায়িত করেন এবং তারপরে কল করেন তবে local_variablesএটি পদ্ধতি আর্গুমেন্ট + সমস্ত স্থানীয় ভেরিয়েবলগুলি ফিরিয়ে দেবে। আপনার কোড যখন এটি ভুল হতে পারে।
আলিয়াক্সেই ক্লিউচনিকিকাউ

5

এটি সহায়ক হতে পারে ...

  def foo(x, y)
    args(binding)
  end

  def args(callers_binding)
    callers_name = caller[0][/`.*'/][1..-2]
    parameters = method(callers_name).parameters
    parameters.map { |_, arg_name|
      callers_binding.local_variable_get(arg_name)
    }    
  end

1
এই সামান্য হল hacky পরিবর্তে callers_nameবাস্তবায়ন, এছাড়াও আপনি পাস পারে __method__বরাবর binding
টম লর্ড

3

আপনি একটি ধ্রুবক যেমন সংজ্ঞায়িত করতে পারেন:

ARGS_TO_HASH = "method(__method__).parameters.map { |arg| arg[1].to_s }.map { |arg| { arg.to_sym => eval(arg) } }.reduce Hash.new, :merge"

এবং এটি আপনার কোডগুলিতে ব্যবহার করুন:

args = eval(ARGS_TO_HASH)
another_method_that_takes_the_same_arguments(**args)

2

আমি আরও যাওয়ার আগে, আপনি foo মধ্যে অনেক আর্গুমেন্ট পাস। দেখে মনে হচ্ছে those সমস্ত যুক্তিই কোনও মডেলের বৈশিষ্ট্য, সঠিক? আপনি সত্যই বস্তু নিজেই পাস করা উচিত। কথার সমাপ্তি।

আপনি একটি "স্প্ল্যাট" যুক্তি ব্যবহার করতে পারেন। এটি সবকিছুকে একটি অ্যারেতে নিক্ষেপ করে। এটি দেখতে যেমন হবে:

def foo(*bar)
  ...
  log.error "Error with arguments #{bar.joins(', ')}"
end

এতে দ্বিমত পোষণ করুন, কোডের পঠনযোগ্যতা এবং পুনঃব্যবহারযোগ্যতার জন্য পদ্ধতি স্বাক্ষর গুরুত্বপূর্ণ। অবজেক্টটি নিজেই ভাল, তবে আপনাকে কোথাও উদাহরণ তৈরি করতে হবে, সুতরাং আপনি পদ্ধতিটি বা পদ্ধতিতে কল করার আগে। আমার মতে পদ্ধতিতে আরও ভাল। যেমন ব্যবহারকারী পদ্ধতি তৈরি করুন।
হারিস ক্রাজিনা

আমার চেয়ে বুদ্ধিমান মানুষকে উদ্ধৃত করার জন্য, বব মার্টিন তাঁর বই, ক্লিন কোড-এ লিখেছেন, "কোনও অনুষ্ঠানের জন্য আর্গুমেন্টের আদর্শ সংখ্যাটি শূন্য (নীলাদিক) Next (ট্রায়ডিক) যেখানেই সম্ভব এড়ানো উচিত three তিনটির বেশি (পলিয়েডিক) খুব বিশেষ ন্যায়সঙ্গততা প্রয়োজন - এবং তারপরে আর ব্যবহার করা উচিত নয় "" আমি যা বলেছিলাম সে তা বলে চলেছে, অনেকগুলি সম্পর্কিত যুক্তি একটি শ্রেণিতে আবৃত করা উচিত এবং একটি বিষয় হিসাবে পাস করা উচিত। এটি একটি ভাল বই, আমি এটির সুপারিশ করছি।
টম এল

এটিতে খুব সূক্ষ্ম বিন্দু রাখার জন্য নয়, তবে এটি বিবেচনা করুন: আপনার যদি মনে হয় যে আপনার আরও / কম / আলাদা আর্গুমেন্টের প্রয়োজন হয় তবে আপনি আপনার এপিআইটি ভেঙে ফেলেছেন এবং প্রতিটি কলটি সেই পদ্ধতিতে আপডেট করতে হবে। অন্যদিকে, আপনি যদি কোনও বস্তু পাস করেন তবে আপনার অ্যাপ্লিকেশনটির অন্যান্য অংশগুলি (বা আপনার পরিষেবার গ্রাহকরা) আনন্দের সাথে চাগতে পারে।
টম এল

আমি আপনার পয়েন্টগুলির সাথে একমত নই এবং যেমন জাভাতে আমি সর্বদা আপনার পদ্ধতির প্রয়োগ করব। তবে আমি মনে করি আরওআর-এর সাথে আলাদা এবং এটি কারণ:
হারিস ক্রাজিনা

আমি আপনার পয়েন্টগুলির সাথে একমত নই এবং যেমন জাভাতে আমি সর্বদা আপনার পদ্ধতির প্রয়োগ করব। তবে আমি মনে করি আরওআর-এর সাথে আলাদা এবং এটি কারণ: আপনি যদি ডিবিতে অ্যাক্টিভেকর্ড সংরক্ষণ করতে চান এবং আপনার কাছে এমন পদ্ধতি রয়েছে যা এটি সংরক্ষণ করে তবে পদ্ধতি সংরক্ষণের জন্য পাস করার আগে আপনাকে হ্যাশ একত্র করতে হবে। ব্যবহারকারীর উদাহরণস্বরূপ আমরা প্রথমে, শেষ নাম, ব্যবহারকারীর নাম, ইত্যাদি সেট করি এবং পদ্ধতি সংরক্ষণের জন্য পাসের হ্যাশের চেয়ে কিছু করতে পারে এবং এটি সংরক্ষণ করবে। এবং এখানে সমস্যাটি হ'ল প্রতিটি বিকাশকারী কীভাবে হ্যাশ রাখবেন তা জানেন? এটি সক্রিয় রেকর্ড যাতে আপনাকে হ্যাশ একত্র করার চেয়ে ডিবি স্কিমাটি দেখতে হবে এবং কোনও চিহ্ন চিহ্ন না এড়াতে খুব যত্নবান হতে হবে।
হারিস ক্রাজিনা

2

আপনি যদি পদ্ধতিটির স্বাক্ষর পরিবর্তন করেন তবে আপনি এর মতো কিছু করতে পারেন:

def foo(*args)
  # some code
  # error happens here
  logger.error "Method has failed, here are all method arguments #{args}"    
end

বা:

def foo(opts={})
  # some code
  # error happens here
  logger.error "Method has failed, here are all method arguments #{opts.values}"    
end

এই ক্ষেত্রে, বিরক্তিকর args বা opts.valuesএকটি অ্যারে হবে, তবে আপনি joinযদি কমাতে পারেন তবে। চিয়ার্স


2

দেখে মনে হচ্ছে যে এই প্রশ্নটি যা করার চেষ্টা করছে তা সবেমাত্র প্রকাশিত একটি রত্ন দিয়েই করা যেতে পারে, https://github.com/ericbeland/exception_details । এটি উদ্ধারকৃত ব্যতিক্রম থেকে স্থানীয় ভেরিয়েবল এবং মান (এবং উদাহরণ ভেরিয়েবল) তালিকাভুক্ত করবে। এক নজরে মূল্যবান হতে পারে ...


1
এটি দুর্দান্ত রত্ন, রেল ব্যবহারকারীদের জন্য আমি মণিরও সুপারিশ করব better_errors
হারিস ক্রাজিনা

1

যদি আপনার একটি হ্যাশ হিসাবে যুক্তিগুলির প্রয়োজন হয় এবং আপনি পরামিতিগুলির কৌশলযুক্ত নিষ্কাশন দিয়ে পদ্ধতির শরীরকে দূষিত করতে না চান তবে এটি ব্যবহার করুন:

def mymethod(firstarg, kw_arg1:, kw_arg2: :default)
  args = MethodArguments.(binding) # All arguments are in `args` hash now
  ...
end

এই প্রকল্পটিকে কেবল আপনার প্রকল্পে যুক্ত করুন:

class MethodArguments
  def self.call(ext_binding)
    raise ArgumentError, "Binding expected, #{ext_binding.class.name} given" unless ext_binding.is_a?(Binding)
    method_name = ext_binding.eval("__method__")
    ext_binding.receiver.method(method_name).parameters.map do |_, name|
      [name, ext_binding.local_variable_get(name)]
    end.to_h
  end
end

0

যদি ফাংশনটি কোনও শ্রেণীর ভিতরে থাকে তবে আপনি এর মতো কিছু করতে পারেন:

class Car
  def drive(speed)
  end
end

car = Car.new
method = car.method(:drive)

p method.parameters #=> [[:req, :speed]] 
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.