พารามิเตอร์เสริม Ruby


121

หากฉันกำหนดฟังก์ชัน Ruby ไว้ดังนี้:

def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil )

ฉันจะเรียกมันว่าจัดหาเฉพาะ 2 อาร์กิวเมนต์แรกและอาร์กิวเมนต์สุดท้ายได้อย่างไร ทำไมถึงไม่เหมือน

ldap_get( base_dn, filter, , X)

เป็นไปได้หรือถ้าเป็นไปได้จะทำได้อย่างไร?

คำตอบ:


131

ตอนนี้ยังใช้ทับทิมไม่ได้ คุณไม่สามารถส่งผ่านแอตทริบิวต์ "ว่าง" ไปยังวิธีการได้ สิ่งที่ใกล้เคียงที่สุดที่คุณจะได้รับคือการผ่านศูนย์:

ldap_get(base_dn, filter, nil, X)

อย่างไรก็ตามสิ่งนี้จะตั้งค่าขอบเขตเป็นศูนย์ไม่ใช่ LDAP :: LDAP_SCOPE_SUBTREE

สิ่งที่คุณทำได้คือตั้งค่าเริ่มต้นภายในวิธีการของคุณ:

def ldap_get(base_dn, filter, scope = nil, attrs = nil)
  scope ||= LDAP::LDAP_SCOPE_SUBTREE
  ... do something ...
end

ตอนนี้ถ้าคุณเรียกวิธีการข้างต้นพฤติกรรมจะเป็นไปตามที่คุณคาดหวัง


21
gotcha เล็ก ๆ น้อย ๆ ด้วยวิธีนี้: เช่นถ้าคุณกำลังพยายามที่จะทำให้ค่าเริ่มต้นสำหรับscopeความจริงและคุณผ่านในfalse, scope ||= trueจะไม่ทำงาน โดยจะประเมินผลเช่นเดียวกับnilและจะกำหนดเป็นtrue
Joshua Pinter

4
เป็นไปได้ไหมกับทับทิมรุ่นปัจจุบัน 3 ปีหลังจากคำตอบนี้
dalloliogm

1
@JoshPinter คำอธิบายที่ดี โดยทั่วไป || = ไม่ได้เป็น = b หรือ C ผม cringed xyz||=trueที่เห็น มันบอกว่าถ้าไม่มีมันก็เป็นจริงเสมอ ถ้าเป็นเรื่องจริงก็จริง
Damon Aw

7
กับทุกคนบอกว่าไม่ดีคือฉันประหลาดใจที่ไม่มีใครได้กล่าวถึงว่าวิธีที่ดีกว่าที่จะทำเช่นนี้คือมีscope ||= true scope = LDAP::LDAP_SCOPE_SUBTREE if scope.nil?แน่นอนว่าแม้จะสมมติว่าnilเป็นค่าที่ไม่ถูกต้อง
Erik Sandberg

1
อัปเดต oldie นี้: อีกทางเลือกหนึ่งคือการใช้เครื่องหมายขีดล่าง nilแต่น่าเสียดายที่มันมีผลเช่นเดียวกับการตั้งค่าพารามิเตอร์ บางคนอาจชอบสัญกรณ์: ldap_get(base_dn, filter, _, X)(หมายเหตุ: ฉันไม่รู้ (ยัง) เมื่อมีการแนะนำใน Ruby เธรด SO ที่น่าสนใจ)
Eric Platon

137

คุณมักจะดีกว่าในการใช้แฮชตัวเลือก

def ldap_get(base_dn, filter, options = {})
  options[:scope] ||= LDAP::LDAP_SCOPE_SUBTREE
  ...
end

ldap_get(base_dn, filter, :attrs => X)

23
กลยุทธ์ทั่วไปคือการมีแฮชตัวเลือกเริ่มต้นและรวมเข้ากับสิ่งที่ส่งผ่าน:options = default_options.merge(options)
นาธานลอง

7
ฉันไม่แนะนำสิ่งนี้เพราะตัวเลือกไม่ได้บอกคุณว่าวิธีการนี้คาดหวังหรือค่าเริ่มต้นคืออะไร
Bron Davies

53

เวลาผ่านไปและตั้งแต่เวอร์ชัน 2 Ruby รองรับพารามิเตอร์ที่มีชื่อ:

def ldap_get ( base_dn, filter, scope: "some_scope", attrs: nil )
  p attrs
end

ldap_get("first_arg", "second_arg", attrs: "attr1, attr2") # => "attr1, attr2"

1
คุณยังสามารถใช้เครื่องหมายคู่เพื่อรวบรวมอาร์กิวเมนต์คำหลักที่ไม่ได้กำหนดเพิ่มเติม สิ่งนี้เกี่ยวข้องกับปัญหานี้: stackoverflow.com/a/35259850/160363
Henry Tseng

3

ldap_getมันเป็นไปไม่ได้ที่จะทำมันในแบบที่คุณได้กำหนดไว้ อย่างไรก็ตามหากคุณกำหนดldap_getเช่นนี้:

def ldap_get ( base_dn, filter, attrs=nil, scope=LDAP::LDAP_SCOPE_SUBTREE )

ตอนนี้คุณสามารถ:

ldap_get( base_dn, filter, X )

แต่ตอนนี้คุณมีปัญหาที่คุณไม่สามารถเรียกมันด้วยอาร์กอนสองตัวแรกและอาร์กิวเมนต์สุดท้าย (ปัญหาเดียวกันกับก่อนหน้านี้ แต่ตอนนี้อาร์กิวเมนต์สุดท้ายแตกต่างกัน)

เหตุผลสำหรับสิ่งนี้ง่ายมาก: ทุกอาร์กิวเมนต์ใน Ruby ไม่จำเป็นต้องมีค่าเริ่มต้นดังนั้นคุณจึงไม่สามารถเรียกมันตามที่คุณระบุไว้ได้ ในกรณีของคุณอาร์กิวเมนต์สองตัวแรกไม่มีค่าเริ่มต้น


1

1) คุณไม่สามารถโอเวอร์โหลดเมธอดได้ ( เหตุใดวิธีการสนับสนุนทับทิมจึงไม่โอเวอร์โหลด ) ดังนั้นทำไมไม่เขียนวิธีการใหม่ทั้งหมด

2) ฉันแก้ไขปัญหาที่คล้ายกันโดยใช้ตัวดำเนินการ splat * สำหรับอาร์เรย์ที่มีความยาวเป็นศูนย์ขึ้นไป จากนั้นถ้าฉันต้องการส่งผ่านพารามิเตอร์ที่ฉันทำได้มันจะถูกตีความว่าเป็นอาร์เรย์ แต่ถ้าฉันต้องการเรียกใช้เมธอดโดยไม่มีพารามิเตอร์ใด ๆ ฉันก็ไม่ต้องผ่านอะไรเลย ดูRuby Programming Languageหน้า 186/187


0

เมื่อเร็ว ๆ นี้ฉันพบวิธีแก้ปัญหานี้ ฉันต้องการสร้างเมธอดในคลาสอาร์เรย์ด้วยพารามิเตอร์ที่เป็นทางเลือกเพื่อเก็บหรือละทิ้งองค์ประกอบในอาร์เรย์

วิธีที่ฉันจำลองสิ่งนี้คือการส่งอาร์เรย์เป็นพารามิเตอร์จากนั้นตรวจสอบว่าค่าที่ดัชนีนั้นเป็นศูนย์หรือไม่

class Array
  def ascii_to_text(params)
    param_len = params.length
    if param_len > 3 or param_len < 2 then raise "Invalid number of arguments #{param_len} for 2 || 3." end
    bottom  = params[0]
    top     = params[1]
    keep    = params[2]
    if keep.nil? == false
      if keep == 1
        self.map{|x| if x >= bottom and x <= top then x = x.chr else x = x.to_s end}
      else
        raise "Invalid option #{keep} at argument position 3 in #{p params}, must be 1 or nil"
      end
    else
      self.map{|x| if x >= bottom and x <= top then x = x.chr end}.compact
    end
  end
end

ลองใช้วิธีการคลาสของเราด้วยพารามิเตอร์ที่แตกต่างกัน:

array = [1, 2, 97, 98, 99]
p array.ascii_to_text([32, 126, 1]) # Convert all ASCII values of 32-126 to their chr value otherwise keep it the same (That's what the optional 1 is for)

เอาท์พุท: ["1", "2", "a", "b", "c"]

โอเคเจ๋งที่ได้ผลตามแผนที่วางไว้ ตอนนี้เรามาตรวจสอบดูว่าจะเกิดอะไรขึ้นถ้าเราไม่ผ่านตัวเลือกพารามิเตอร์ที่สาม (1) ในอาร์เรย์

array = [1, 2, 97, 98, 99]
p array.ascii_to_text([32, 126]) # Convert all ASCII values of 32-126 to their chr value else remove it (1 isn't a parameter option)

เอาท์พุท: ["a", "b", "c"]

อย่างที่คุณเห็นอ็อพชันที่สามในอาร์เรย์ถูกลบออกไปแล้วดังนั้นการเริ่มต้นส่วนอื่นในวิธีการและลบค่า ASCII ทั้งหมดที่ไม่อยู่ในช่วงของเรา (32-126)

อีกวิธีหนึ่งคือเราสามารถออกค่าเป็นศูนย์ในพารามิเตอร์ได้ ซึ่งจะมีลักษณะคล้ายกับบล็อกรหัสต่อไปนี้:

def ascii_to_text(top, bottom, keep = nil)
  if keep.nil?
    self.map{|x| if x >= bottom and x <= top then x = x.chr end}.compact
  else
    self.map{|x| if x >= bottom and x <= top then x = x.chr else x = x.to_s end}
end

-1

เป็นไปได้ :) แค่เปลี่ยนนิยาม

def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil )

ถึง

def ldap_get ( base_dn, filter, *param_array, attrs=nil )
scope = param_array.first || LDAP::LDAP_SCOPE_SUBTREE

ขอบเขตจะอยู่ในอาร์เรย์เป็นที่แรก เมื่อคุณระบุ 3 อาร์กิวเมนต์คุณจะได้กำหนด base_dn, filter and attrs และ param_array จะเป็น [] เมื่ออาร์กิวเมนต์ 4 ตัวขึ้นไป param_array จะเป็น [อาร์กิวเมนต์ 1 หรือมากกว่าและเพิ่มเติม]

ข้อเสียคือ ... มันเป็นวิธีแก้ปัญหาที่ไม่ชัดเจนน่าเกลียดจริงๆ นี่คือคำตอบว่าเป็นไปได้ที่จะ ommit อาร์กิวเมนต์ที่อยู่ตรงกลางของ function call ใน Ruby :)

สิ่งที่คุณต้องทำอีกอย่างคือการเขียนค่าเริ่มต้นของขอบเขตใหม่


4
การแก้ปัญหานี้ผิดอย่างสิ้นเชิง เป็นข้อผิดพลาดทางไวยากรณ์ในการใช้พารามิเตอร์ค่าเริ่มต้น ( attrs=nil) หลังเครื่องหมาย ( *param_array)
Erik Sandberg

3
-1: เอริกถูกต้อง ทำให้เกิดข้อผิดพลาดทางไวยากรณ์ใน irb 2.0.0p247 ตามภาษาการเขียนโปรแกรม Rubyใน Ruby 1.8 พารามิเตอร์ splat จะต้องเป็นค่าสุดท้ายยกเว้น an &parameterแต่ใน Ruby 1.9 นั้นสามารถตามด้วย "พารามิเตอร์ธรรมดา" ได้เช่นกัน ในทั้งสองกรณีไม่มีพารามิเตอร์ที่มีกฎหมายดีฟอลต์หลังพารามิเตอร์ที่มีเครื่องหมาย
andyg0808

ภาษาการเขียนโปรแกรม Ruby หน้า 186/187 เครื่องหมายสามารถใช้ได้กับวิธีการ จะต้องเป็นพารามิเตอร์สุดท้ายในวิธีการเว้นแต่จะใช้ &
rupweb

AndyG ถูกต้องคำสั่งต้องเป็น: def ldap_get (base_dn, filter, attrs = nil, * param_array)
rupweb

-1

คุณสามารถทำได้ด้วยแอปพลิเคชันบางส่วนแม้ว่าการใช้ตัวแปรที่ตั้งชื่อจะนำไปสู่โค้ดที่อ่านได้มากขึ้น John Resig เขียนบทความบล็อกในปี 2008 เกี่ยวกับวิธีการทำใน JavaScript: http://ejohn.org/blog/partial-functions-in-javascript/

Function.prototype.partial = function(){
  var fn = this, args = Array.prototype.slice.call(arguments);
  return function(){
    var arg = 0;
    for ( var i = 0; i < args.length && arg < arguments.length; i++ )
      if ( args[i] === undefined )
        args[i] = arguments[arg++];
    return fn.apply(this, args);
  };
};

อาจเป็นไปได้ที่จะใช้หลักการเดียวกันนี้ใน Ruby (ยกเว้นการสืบทอดต้นแบบ)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.