রুবির এক শ্রেণীর সমস্ত বংশধরকে সন্ধান করুন


144

আমি খুব সহজেই রুবিতে শ্রেণি শ্রেণিবিন্যাস আরোহণ করতে পারি:

String.ancestors     # [String, Enumerable, Comparable, Object, Kernel]
Enumerable.ancestors # [Enumerable]
Comparable.ancestors # [Comparable]
Object.ancestors     # [Object, Kernel]
Kernel.ancestors     # [Kernel]

বংশগতি অবতরণ করার কি কোনও উপায় আছে? আমি এটি করতে চাই

Animal.descendants      # [Dog, Cat, Human, ...]
Dog.descendants         # [Labrador, GreatDane, Airedale, ...]
Enumerable.descendants  # [String, Array, ...]

তবে সেখানে কোনও descendantsপদ্ধতি বলে মনে হচ্ছে না ।

(এই প্রশ্নটি উত্থাপিত হয়েছে কারণ আমি একটি বেইল ক্লাস থেকে অবতরণ করে একটি রেল অ্যাপ্লিকেশনটিতে সমস্ত মডেলগুলি সন্ধান করতে চাই এবং তাদের তালিকাভুক্ত করতে চাই; আমার কাছে এমন একটি কন্ট্রোলার রয়েছে যা এই জাতীয় কোনও মডেলের সাথে কাজ করতে পারে এবং আমি নতুন মডেল যুক্ত করতে সক্ষম হতে চাই নিয়ামকটি পরিবর্তন না করেই))

উত্তর:


146

এখানে একটি উদাহরণ:

class Parent
  def self.descendants
    ObjectSpace.each_object(Class).select { |klass| klass < self }
  end
end

class Child < Parent
end

class GrandChild < Child
end

puts Parent.descendants
puts Child.descendants

প্যারেন্ট.ডেসেন্ডেন্টস আপনাকে দেয়:

GrandChild
Child

চাইল্ড.ডেসেন্ডেন্টস আপনাকে দেয়:

GrandChild

1
এটি দুর্দান্ত কাজ করে, ধন্যবাদ! আমি মনে করি আপনি যদি মিলিসেকেন্ড শেভ করতে চেষ্টা করেন তবে প্রতিটি ক্লাসে যাওয়া খুব ধীর হতে পারে তবে এটি আমার পক্ষে পুরোপুরি দ্রুত।
ডগলাস কাঠবিড়ালি

1
singleton_classClassএটি আরও দ্রুত করার পরিবর্তে ( apidock.com/rails/Class/descendants এ উত্স দেখুন )
ব্রুলিওো

21
সতর্কতা অবলম্বন করুন যদি আপনার এমন কোনও পরিস্থিতি হতে পারে যেখানে ক্লাসটি এখনও মেমরিতে লোড করা হয়নি, ObjectSpaceতা না করে।
এডমন্ড লি

আমি কীভাবে এই কাজটি করতে পারি Objectএবং BasicObject
?,

@ আমলপুজারি p ObjectSpace.each_object(Class)সমস্ত ক্লাস প্রিন্ট করবে। selfপদ্ধতিতে কোডের লাইনে নামটি বাদ দিয়ে আপনি যে কোনও শ্রেণির বংশধরদেরও পেতে পারেন get
ববরোডস

62

আপনি যদি রেল> = 3 ব্যবহার করেন তবে আপনার কাছে দুটি বিকল্প আছে have .descendantsআপনি যদি শিশুদের ক্লাসগুলির এক স্তরের বেশি গভীরতা চান তবে ব্যবহার করুন বা শিশু স্তরগুলির .subclassesপ্রথম স্তরের জন্য ব্যবহার করুন ।

উদাহরণ:

class Animal
end

class Mammal < Animal
end

class Dog < Mammal
end

class Fish < Animal
end

Animal.subclasses #=> [Mammal, Fish] 
Animal.descendants  #=> [Dog, Mammal, Fish]

6
নোট করুন যে বিকাশে আপনার যদি আগ্রহী লোডিং বন্ধ হয়ে যায়, এই পদ্ধতিগুলি কেবল তখনই ক্লাসগুলি ফেরত পাঠানো হবে যদি সেগুলি লোড করা হয় (যেমন যদি তারা ইতিমধ্যে চলমান সার্ভার দ্বারা রেফারেন্স করা হয়েছে)।
স্টিফেন.হ্যানসন

1
@ স্টিফেন.হ্যানসন এখানে সঠিক ফলাফলের গ্যারান্টি দেওয়ার সবচেয়ে নিরাপদ উপায় কী?
ক্রিস এডওয়ার্ডস

26

নিবিটি শৃঙ্খলিত পুনরাবৃত্তকারীগুলির সাথে রুবি ১.৯ (বা 1.8.7):

#!/usr/bin/env ruby1.9

class Class
  def descendants
    ObjectSpace.each_object(::Class).select {|klass| klass < self }
  end
end

রুবি প্রাক-1.8.7:

#!/usr/bin/env ruby

class Class
  def descendants
    result = []
    ObjectSpace.each_object(::Class) {|klass| result << klass if klass < self }
    result
  end
end

এটি এর মতো ব্যবহার করুন:

#!/usr/bin/env ruby

p Animal.descendants

3
এটি মডিউলগুলির জন্যও কাজ করে; কোডের "মডিউল" দিয়ে কেবল "ক্লাস" এর উভয় দৃষ্টান্ত প্রতিস্থাপন করুন।
কোরিনেতে

2
অতিরিক্ত সুরক্ষার জন্য একজনকে লেখা উচিত ObjectSpace.each_object(::Class)- আপনার কোডটি :: ক্লাস সংজ্ঞায়িত হওয়ার পরে কোডটি কার্যকর রাখবে।
রিনি সরসু

19

উত্তরাধিকার সূত্রে শ্রেণীবদ্ধ পদ্ধতি ওভাররাইড করুন । এই পদ্ধতিটি সাবক্লাসটি পাস করার পরে এটি তৈরি করা হবে যা আপনি ট্র্যাক করতে পারেন।


আমি এইটাও পছন্দ করি. পদ্ধতিটি ওভাররাইড করা প্রান্তিকভাবে হস্তক্ষেপজনক তবে আপনাকে প্রতি বর্গ পরিদর্শন করতে হবে না বলে এটি বংশধরদের পদ্ধতিটিকে আরও কিছুটা দক্ষ করে তোলে।
ডগলাস কাঠবিড়ালি

@ ডগলাস এটি কম অনুপ্রেরণামূলক হলেও, এটি সম্ভবত আপনার প্রয়োজনীয়তা পূরণ করে কিনা তা দেখার জন্য আপনাকে পরীক্ষা করতে হবে (অর্থাত্ কারা কারা কন্ট্রোলার / মডেল শ্রেণিবদ্ধতা তৈরি করে?)।
জোশ লি

এটি নন-এমআরআই রুবি বাস্তবায়নের জন্য আরও পোর্টেবল, যার মধ্যে কিছুতে অবজেক্টস্পেস ব্যবহার থেকে গুরুতর পারফরম্যান্স ওভারহেড রয়েছে। ক্লাস # উত্তরাধিকার সূত্রে রুবিতে "স্ব-নিবন্ধকরণ" নিদর্শনগুলি প্রয়োগ করার জন্য আদর্শ।
জন হুইটলি

একটি উদাহরণ শেয়ার করতে যত্নশীল? যেহেতু এটি শ্রেনীর স্তর হিসাবে আমি অনুমান করি যে আপনাকে প্রতিটি শ্রেণি কোনও না কোনও গ্লোবাল ভেরিয়েবলের মধ্যে সঞ্চয় করতে হবে?
Noz

@ নোজ ন, ক্লাসে নিজেই একটি উদাহরণ পরিবর্তনশীল। কিন্তু তারপরে জিসি দ্বারা বস্তুগুলি সংগ্রহ করা যায় না।
ফ্রোগজ

13

বিকল্পভাবে (রুবি 1.9+ এর জন্য আপডেট হয়েছে):

ObjectSpace.each_object(YourRootClass.singleton_class)

রুবি 1.8 সামঞ্জস্যপূর্ণ উপায়:

ObjectSpace.each_object(class<<YourRootClass;self;end)

মনে রাখবেন এটি মডিউলগুলির জন্য কাজ করবে না। এছাড়াও, আপনার রুটক্লাস উত্তরের অন্তর্ভুক্ত করা হবে। আপনি অ্যারে # ব্যবহার করতে পারেন - বা এটি অপসারণের অন্য কোনও উপায়।


সেটি অসাধারণ ছিল. আপনি আমাকে ব্যাখ্যা করতে পারেন যে কিভাবে কাজ করে? আমি ব্যবহার করেছিObjectSpace.each_object(class<<MyClass;self;end) {|it| puts it}
ডেভিড ওয়েস্ট

1
রুবি ১.৮-এ, class<<some_obj;self;endকোনও অবজেক্টের সিঙ্গলটন_ক্লাস প্রদান করে। 1.9+ এ আপনি some_obj.singleton_classপরিবর্তে ব্যবহার করতে পারেন (এটি প্রতিফলিত করতে আমার উত্তর আপডেট করেছে)। প্রতিটি বস্তু এটির সিঙ্গলটন_ক্লাসের উদাহরণ, যা ক্লাসগুলির জন্যও প্রযোজ্য। যেহেতু প্রতিটি_বজেক্ট (সামারক্লাস) সামারক্লাসের সমস্ত দৃষ্টিকোণ দেয় এবং সামার ক্লাস সামারক্লাস.সেনলেটন_ক্লাসের একটি উদাহরণ, প্রতিটি_বজেক্ট (সামারক্লাস.সেনলেটন_ক্লাস) সোমকলাস এবং সমস্ত সাবক্লাস প্রদান করবে।
এপিয়ারস

10

যদিও অবজেক্টস্পেস কাজ করে তবে উত্তরাধিকার সূত্রে প্রাপ্ত শ্রেণি পদ্ধতিটি উত্তরাধিকার সূত্রে প্রাপ্ত (সাবক্লাস) রুবি ডকুমেন্টেশন

অবজেক্টস্পেস মূলত যে কোনও কিছু এবং বর্তমানে বরাদ্দ মেমরির ব্যবহার করা সমস্ত কিছু অ্যাক্সেস করার একটি উপায়, সুতরাং এটির প্রতিটি উপাদানকে পুনরুক্ত করে এটি প্রাণী শ্রেণীর একটি সাবগ্লাস কিনা তা পরীক্ষা করার জন্য আদর্শ নয়।

নীচের কোডে, উত্তরাধিকারসূত্রে প্রাপ্ত অ্যানিম্যাল ক্লাস পদ্ধতিটি একটি কলব্যাক প্রয়োগ করে যা তার বংশধরের অ্যারেতে নতুনভাবে নির্মিত সাবক্লাস যুক্ত করবে।

class Animal
  def self.inherited(subclass)
    @descendants = []
    @descendants << subclass
  end

  def self.descendants
    puts @descendants 
  end
end

6
`@ ডিজাইনসেন্টস || = []` অন্যথায় আপনি কেবল শেষ বংশধর পাবেন
অ্যাক্সেল টেটজল্যাফ

4

আমি জানি আপনি উত্তরাধিকার সূত্রে কীভাবে এটি করবেন তা জিজ্ঞাসা করছেন তবে ক্লাসের নাম ফাঁক করে আপনি সরাসরি রুবিতে এটি অর্জন করতে পারেন ( Classবা Module)

module DarthVader
  module DarkForce
  end

  BlowUpDeathStar = Class.new(StandardError)

  class Luck
  end

  class Lea
  end
end

DarthVader.constants  # => [:DarkForce, :BlowUpDeathStar, :Luck, :Lea]

DarthVader
  .constants
  .map { |class_symbol| DarthVader.const_get(class_symbol) }
  .select { |c| !c.ancestors.include?(StandardError) && c.class != Module }
  # => [DarthVader::Luck, DarthVader::Lea]

ObjectSpaceঅন্যান্য সমাধানের প্রস্তাবের মতো প্রতিটি শ্রেণীর সাথে তুলনা করার চেয়ে এই পদ্ধতিটি আরও দ্রুত ।

উত্তরাধিকারের ক্ষেত্রে আপনার যদি গুরুতরভাবে এটির প্রয়োজন হয় তবে আপনি এরকম কিছু করতে পারেন:

class DarthVader
  def self.descendants
    DarthVader
      .constants
      .map { |class_symbol| DarthVader.const_get(class_symbol) }
  end

  class Luck < DarthVader
    # ...
  end

  class Lea < DarthVader
    # ...
  end

  def force
    'May the Force be with you'
  end
end

মানদণ্ডগুলি এখানে: http://www.eq8.eu/blogs/13-ruby-ancestors-descendants- এবং- other-annoying- relatives

হালনাগাদ

শেষ পর্যন্ত আপনাকে যা করতে হবে তা হ'ল

class DarthVader
  def self.inherited(klass)
    @descendants ||= []
    @descendants << klass
  end

  def self.descendants
    @descendants || []
  end
end

class Foo < DarthVader
end

DarthVader.descendants #=> [Foo]

আপনাকে পরামর্শ দেওয়ার জন্য @ স্যাটার্নফ্লায়ারকে ধন্যবাদ


3

(রেলস <= 3.0) বিকল্পভাবে আপনি অ্যাক্টিভাস্পোর্ট :: ডেসেন্ডেন্টস ট্র্যাকার ব্যবহার করতে পারেন। উত্স থেকে:

এই মডিউলটি বংশধরদের ট্র্যাক করার জন্য একটি অভ্যন্তরীণ বাস্তবায়ন সরবরাহ করে যা অবজেক্টস্পেসের মাধ্যমে পুনরাবৃত্ত হওয়ার চেয়ে দ্রুত।

যেহেতু এটি দুর্দান্তভাবে মডিউলাইজ হয়েছে তাই আপনি আপনার রুবি অ্যাপ্লিকেশনের জন্য সেই বিশেষ মডিউলটি কেবল 'চেরি-পিক' করতে পারেন।


2

রুবি মুখের ক্লাস # বংশধর রয়েছে,

require 'facets/class/descendants'

এটি একটি জেনারাল দূরত্বের প্যারামিটারকে সমর্থন করে।


2

একটি সাধারণ সংস্করণ যা শ্রেণীর সমস্ত বংশধরের একটি অ্যারে দেয়:

def descendants(klass)
  all_classes = klass.subclasses
  (all_classes + all_classes.map { |c| descendants(c) }.reject(&:empty?)).flatten
end

1
এটি দেখতে একটি সেরা উত্তর বলে মনে হচ্ছে like দুর্ভাগ্যক্রমে এটি এখনও ক্লাসের অলস-লোডিংয়ের শিকার হয়। তবে আমি মনে করি তারা সবাই করে।
ডেভ মোর্স

@ ডেভমর্স আমি ফাইলগুলির তালিকা তৈরি করতে এবং ম্যানুয়ালি কনস্ট্যান্টগুলি তাদের বংশধর হিসাবে নিবন্ধিত করার জন্য লোড করে শেষ করেছি (এবং তারপরে এই পুরো জিনিসটি সরিয়ে শেষ করেছি: ডি)
ডোরিয়ান

1
নোট যা #subclassesরেলস অ্যাক্টিভসপোর্ট থেকে ort
অ্যালেক্স

1

আপনি require 'active_support/core_ext'এবং descendantsপদ্ধতিটি ব্যবহার করতে পারেন । দস্তাবেজটি পরীক্ষা করে দেখুন এবং আইআরবি বা পিসি তে একটি শট দিন। রেল ছাড়া ব্যবহার করা যেতে পারে।


1
আপনি যদি আপনার জেমফাইলে সক্রিয় সমর্থন যোগ করতে চান তবে এটি আসলে "রেল ছাড়া" নয় not এটি কেবল আপনার পছন্দসই রেলগুলি বেছে নিচ্ছে।
কালেব

1
এটি এখানে একটি দার্শনিক স্পর্শকাতর মতো মনে হয় যা এখানে প্রাসঙ্গিক নয়, তবে আমি মনে করি যে একটি রেল উপাদান ব্যবহার করার অর্থ এই যে using Railsএটি একটি সামগ্রিক অর্থে।
thelostspore

0

রেলগুলি প্রতিটি বস্তুর জন্য একটি সাবক্লাস পদ্ধতি সরবরাহ করে তবে এটি ভালভাবে নথিভুক্ত নয়, এবং এটি কোথায় সংজ্ঞায়িত হয়েছে তা আমি জানি না। এটি স্ট্রিং হিসাবে শ্রেণীর নামের একটি অ্যারে প্রদান করে।


0

ব্যবহার descendants_tracker মণি সাহায্য করতে পারে। রত্নটির দস্তাবেজ থেকে নিম্নলিখিত উদাহরণটি অনুলিপি করা হয়েছে:

class Foo
  extend DescendantsTracker
end

class Bar < Foo
end

Foo.descendants # => [Bar]

এই রত্নটি জনপ্রিয় ভার্চুয়াস রত্ন ব্যবহার করে , তাই আমি মনে করি এটি বেশ শক্ত।


0

এই পদ্ধতিটি কোনও অবজেক্টের বংশধরের সমস্ত একটি বহুমাত্রিক হ্যাশ ফিরিয়ে দেবে।

def descendants_mapper(klass)
  klass.subclasses.reduce({}){ |memo, subclass|
    memo[subclass] = descendants_mapper(subclass); memo
  }
end

{ MasterClass => descendants_mapper(MasterClass) }

-1

কোনও সাবক্লাস লোড হওয়ার আগে যদি আপনার কোডটিতে অ্যাক্সেস থাকে তবে আপনি উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতিটি ব্যবহার করতে পারেন ।

যদি আপনি না করেন (যা কোনও মামলা নয় তবে এটি যে কেউ এই পোস্টটি খুঁজে পেয়েছিল তার পক্ষে এটি কার্যকর হতে পারে) আপনি কেবল লিখতে পারেন:

x = {}
ObjectSpace.each_object(Class) do |klass|
     x[klass.superclass] ||= []
     x[klass.superclass].push klass
end
x[String]

দুঃখিত যদি আমি বাক্য গঠনটি মিস করি তবে ধারণাটি পরিষ্কার হওয়া উচিত (এই মুহূর্তে আমার কাছে রুবি অ্যাক্সেস নেই)।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.