Ruby attr_accessor :name to :name[] array - ruby

How would I create an attr_accessor to array?
for example
class MyClass
attr_accessor :my_attr_accessor
def initialize()
end
def add_new_value(new_array)
#my_attr_accessor += new_array
return #my_attr_accessor
end
end
my_class = MyClass.new
my_class.my_attr_accessor = 1
my_class.my_attr_accessor[1] = 2
my_class.my_attr_accessor.push = 3
my_class.add_new_value(5)
my_class.my_attr_accessor
=> [1, 2, 3, 5]

Just use an instance variable that points to an array and make an accessor from that instance variable.
Inside your class include something like this:
attr_accessor :my_attr_accessor
def initialize
#my_attr_accessor = []
end
Note that usingattr_accessor will allow you to change the value of the variable. If you want to ensure that the array stays, use attr_reader in place of attr_accessor. You will still be able to access and set array elements and perform operations on the array but you won't be able to replace it with a new value and using += for concatenation will not work.

If you are OK with the Array always existing, #david4dev's answer is good. If you only want the array to pop into existence on the first usage, and never want the user to be able to replace it with a new array (via assignment):
class MyClass
def my_attr_accessor
#my_attr_accessor ||= []
end
def add_new_value( value )
my_attr_accessor << value
end
def add_new_values( values_array )
my_attr_accessor.concat values_array
end
end
The user could still call my_class.my_attr_accessor.replace( [] ) to wipe it out.

Related

How to use 'attr_accesor'

I have a class with a private method:
class MyClass
attr_accessor :my_attr
def some_mth?(num)
# I want to use my_attr as a variale #myattr here
#and here i want to check if arr include num
#myattr.include?(num)
end
private
def some_pvt_mth
#myattr = [1,2,3,4]
for example generation array here
end
end
When I call #myattr inside some_mth, my variable #myattr is nil
How to use variable #myatt inside class, in every method is it possible?
How do I do it properly?
You do not need to define attr_accessor in order to use an instance variable within the defined class. It's purpose is to create a 'getter' and a 'setter' method, but those are only needed for other classes to access the data.
This is a class:
class Foo
def initialize
#my_attr = [1,2,3,4]
end
def attr_includes?(x)
#my_attr.include?(x)
end
end
There's no attr accessor, but this will work.
The attr accessor essentially includes this code in your class...
class Foo
def my_attr
#my_attr
end
def my_attr=(x)
#my_attr = x
end
end
But if you don't want that, you can just leave it out, and access the variable via other methods (such as your include example).
You have to define the instance variable value first:
class MyClass
attr_accessor :my_attr
def initialize
#myattr = [1, 2, 3, 4]
end
def some_mth?(num)
#myattr.include?(num)
end
end

ruby: validate input before appending to array

I have a ruby class that has an Array as one of its instance variables. I'm trying to figure out how to validate data that is being pushed onto the array.
class Something
def things
#things ||= Array.new
end
end
So I can declare an instance and add stuff to the array pretty easily this way.
#s = Something.new
#s.things << "one"
#s.things << "two"
I tried to create a class method named things<<(inString) to handle the validation but that is not valid syntax. So what approach can I take?
Try something like:
things << data if valid?(data)
where valid? is your validation method.
Example:
...
# will push only when quantity is greater than 0
def push(quantity)
things << item if valid?(quantity)
end
private
def valid?(number)
number > 0
end
If you want to have you own ThingsArray just create an Array subclass and override the push (<<) method to make the validation before pushing:
class ThingsArray < Array
def << (item)
return unless valid?(item)
super
end
private
def valid?(item)
item > 0
end
end
class Something
def things
#things ||= ThingsArray.new
end
end
How about this?
class MyThings < Array
def << (item)
# do your validation with item
self.push(item) if item.valid?
end
end
class Something
def things(item)
#things ||= MyThings.new
end
end

Ruby - Can variable set equal to object of custom class transfer custom class to the variable?

class New_Class
def initialize
#array = ['1A','2A','1B','2C']
end
def remove_letters
#array.map do |rmv|
rmv.sub /([0-9])([A-Z])/, '\1'
end
end
def show_array
#array.each do |element|
puts element
end
end
end
array = New_Class.new
new_array = array.remove_letters
puts new_array.class #=> Array
new_array.each do |element|
puts element #=>1,2,1,2
end
array.show_array #=>1A,2A,1B,2C
new_array.show_array #=>Undefined method error since it's an object of type Array not New_Class
How would I make new_array an object of type New_Class instead of Array?
This doesn't work:
new_array = New_Class.new
new_array = array.remove_letters
Still says new_array is of type Array.
I played around with clone and dup but couldn't get it to work that way either. Thanks!
Your remove_letters method returns an array, which you then assign to new_array. If you want new_array to be another instance of New_Class instead, then you need to return another instance of NewClass from your remove_letters method, not an array:
def initialize(values = ['1A','2A','1B','2C'])
#array = values
end
def remove_letters
New_Class.new(#array.map { |rmv| rmv.sub(/([0-9])([A-Z])/, '\1') })
end
Above, I modify initialize to use your array as a default, if an initial array value isn't passed to New_Class.new, then it uses ['1A','2A','1B','2C'] as a default.

Ruby make 2 different constructors with same ammount of parameters [duplicate]

This question already has answers here:
In Ruby is there a way to overload the initialize constructor?
(7 answers)
Closed 9 years ago.
I've got a class just like this:
class Equipment
attr_reader :text
attr_reader :name
attr_reader :array1
attr_reader :number
end
then, I want to make 2 constructors with 3 parameters each:
1º one -> (text,name,array1)
2º one -> (text, name,number)
The first one as an argument has an array and the other one has an integer (1,2...), so I need to define both constructors so when I create an object of this class it makes a difference between array or integer as the 3º argument.
Any ideas?
EDIT.: I thought this:
def initialize(text = "", name = "", array = array.new, number =0)
#text = text
#name = name
#array1 = array
#number = number
end
(initializing all of them) then:
def Equipment.newc_witharray(sometext, somename, somearray)
#text = sometext
#name = somename
#array1 = somearray
end
def Equipment.newc_withint(sometext, somename, somenumber)
#text = text
#name = name
#number = somenumber
end
and finally calling objects like this:
character1 = Equipment.newc_withint("Barbarian", "conan", 3)
shouldn't this work?
You can create as many constructors as you want on the class with whatever name you want. There is one constructor new, which is inherited from Object, and that can be used to write other constructors. What other answers mention as the constructor, namely the instance method initialize is not a constructor. That is the method called by the constructor method new by default.
class Foo
def self.new1 text, name, array1
obj = new
# do something on obj with text, name, array1
obj
end
def self.new2 text, name, number
obj = new
# do something on obj with text, name, number
obj
end
end
Foo.new1(text, name, array1)
Foo.new2(text, name, number)
There are various ways to achieve this.
Hash arguments
You could pass a hash and extract the values you're interested in:
def initialize(options={})
#text = options.fetch(:text) # raises KeyError if :text is missing
#name = options.fetch(:name) # raises KeyError if :name is missing
#array = options.fetch(:array, []) # returns [] if :array is missing
#number = options.fetch(:number, 0) # returns 0 if :number is missing
end
Keyword arguments
In Ruby 2.0 you can use keyword arguments with default values:
def initialize(text: text, name: name, array: [], number: 0)
#text = text
#name = name
#array = array
#number = number
end
Switching on argument type
This makes the method harder to read, but would work, too:
def initialize(text, name, number_or_array)
#text = text
#name = name
#number = 0
#array = []
case number_or_array
when Integer then #number = number_or_array
when Array then #array = number_or_array
else
raise TypeError, "number_or_array must be a number or an array"
end
end
Built into the language, no, Ruby does not give you that ability.
However, if you want that ability, I would create an initialize method which takes a hash as its parameter. Then you could create an instance of the class using any number of parameters.
E.g:
class Equipment
attr_reader :text, :name, :array1, :number
def initialize(options)
[:text, :name, :array1, :number].each do |sym|
self.send(sym) = options[sum]
end
end
end
The ruby interpreter wouldn't be able to differentiate between the constructors, as the types are not known until runtime :(
However, you can use a very nice workaround:
class Foobar
def initialize(h) # <-- h is a hash
# pass combination of params into the hash, do what you like with them
end
end
and then, using this pattern, you can pass any combination of params into the constructor:
foobar = Foobar.new(:foo => '5', :bar => 10, :baz => 'what?')

Boolean methods in Ruby?

In order to ask something like:
MyClass::create().empty?
How would I set up empty within MyClass?
Empty (true/false) depends on whether a class variable #arr is empty or not.
The question mark is actually part of the method name, so you would do this:
class MyClass
def empty?
#arr.empty? # Implicitly returned.
end
end
Exactly the same as I showed in the last post, but with a different method name.
First, create must return something with an empty? method. For example:
class MyClass
def self.create
[]
end
end
If you want to be operating on instances of MyClass as per your last question:
class MyClass
def self.create
MyClass.new
end
def initialize
#arr = []
end
def empty?
#arr.empty?
end
def add x
#arr << x
self
end
end
Here MyClass acts as a simple wrapper around an array, providing an add method.
pry(main)> MyClass.create.empty?
=> true
You might also need to check whether #arr is nil or not. This depends on your class definition of empty.
def empty?
!#arr || #arr.empty?
end
You could use Forwardable to delegate empty? from your class to the array:
require "forwardable"
class MyClass
extend Forwardable
def_delegators :#arr, :empty?
def initialize(arr)
#arr = arr
end
end
my_object = MyClass.new([])
my_object.empty? # => true

Resources