Ruby: retrieves stack functions from an Array class

I have a need to use a Stack-like data structure for the program I am writing, and I know that Ruby does not have an explicit Stack data structure, but the Array class has all the properties that make a Stack: push , pop , size , clear , isEmpty , inspect , to_s .

When searching the Internet, I found various posts using this syntax to extract the functions of the Array class into a subclass:

 Stack = Array.extract([ :push, :pop, :size, :clear, :inspect, :to_s ]) s = Stack.new s.push 1 s.push 2 s.push 3 s # => [1, 2, 3] s.pop # => 3 s # => [1, 2] 

I would like to do something similar to this, so my Array subclass is limited to what it can do, but it looks like the extract method is no longer in the Array class API.

Questions:

  • This feature has been removed for some reason, what is the detriment to something like this?
  • How can you implement similar functionality with Ruby 1.9.3? Right now, I'm just delegating the calls I need for the Array class, but all the other methods in the Array class can still be called on my Stack object, which I don't want to allow.
+4
source share
3 answers

Take this code, for example:

 class Stack def initialize @array = [] end def push val @array.push val end def pop @array.pop end end 

Here you have a private instance of var to which you delegate the selected methods. Other methods cannot be called directly. The syntax can be sweetened and made more "rubesque" with some metaprogramming, but the basic idea is as shown above.

Of course, you can always get to this private var via instance_variable_get , and there is nothing you can do about it. This is Ruby!

Make a clean, secure public interface. And if someone tries to interfere in the internal parts and breaks something, this is his problem.

Update

If you are using ActiveSupport (which comes with Rails), then there is an easier way to do this.

 # load ActiveSupport if not in Rails env require 'active_support/core_ext' class Stack def initialize @impl = [] end # the "extract" part :) delegate :count, :push, :pop, to: :@impl end s = Stack.new s.push(3).push(4) s.count # => 2 

Or see a similar answer from @AndrewGrimm.

+8
source

If you intend to do a lot of delegation, you can use Ruby delegation methods.

 require "forwardable" class Stack extend Forwardable def_delegators :@array, :push, :pop def initialize @array = [] end end 

Not only does this mean less text input, but if you are familiar with Forwardable , it is easier to read. You know that your class simply delegates, without having to read the code for Stack#push or Stack#pop .

+4
source

Perhaps you can cancel methods that you don't like, although it looks wired.

 class Stack < Array DISLIKE_IMS = instance_methods - Object.instance_methods - [:public, :pop, :size, :to_s, :inspect, :clear] DISLIKE_CMS = methods - Object.methods DISLIKE_IMS.each do |im| class_eval "undef #{im}" end DISLIKE_CMS.each do |cm| instance_eval "undef #{cm}" end end 
0
source

Source: https://habr.com/ru/post/1403492/


All Articles