How to get parent instance value in to child class in ruby? - ruby

I'm not able to get the instance values of parent class to the child class, My code is like this.
class TimeLine
attr_accessor :tweets
def initialize(tweets=[])
#tweets = tweets
end
def print
puts tweets.join("\n")
end
end
class AuthenticateTimeLine < TimeLine
def print
authenticate!
super
end
def authenticate!
puts "authenticated!"
end
end
TimeLine.new([1,2,3,4,5])
authenticate_timeline = AuthenticateTimeLine.new
authenticate_timeline.print
When I call super on the child class, I'm getting empty array.

It's because you initialize it with empty array, you don't pass any argument to AuthenticateTimeLine.new, so default [] is taken (compare your TimeLine#initialize method). If you passed your array as argument, it would work:
authenticate_timeline = AuthenticatateTimeLine.new([1,2,3,4,5])
authenticate_timeline.print
# 'Works' now!

Related

How to pass class method as parameter?

I want to pass a class method to another function, how can I do that?
class A
def A.test(data)
puts data
end
end
def ps(fun)
fun(3)
end
ps(A.test)
You have to use the right getter to receive the method object:
class A
def A.test(data)
puts data
end
end
def ps(fun)
fun.call(3)
end
ps(A.method(:test)) #=> 3
The method method returns the method-object, which can be executed with call.
You can pass just the method_name to ps and have ps send the method_name message to the A class (and always the A class) using this:
class A
def A.test(data)
puts data
end
end
def ps(method_name)
A.send(method_name, 3)
end
ps(:test) # => 3
Or you can pass both the A class and the method_name to ps using this:
class A
def A.test(data)
puts data
end
end
def ps(klass, method_name)
klass.send(method_name, 3)
end
ps(A, :test) # => 3

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

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

Ruby: How to set instance variables from a class method?

I'm not sure that's the right title for this question, but I don't know how else to ask it. I have classes that need to be registered globally so they can be called later. I have most of it working except for a very important part. When the child inherits from the parent class, it registers a new instance, but when the on_message class method is called, I can't figure out how to set the instance variables that I need.
class MyExtension < ExtensionBase
on_message '/join (.+)' do |username|
# this will be a callback function used later
end
end
class ExtensionBase
def self.inherited(child)
MainAppModule.registered_extensions << child.new
end
def self.on_message(string, &block)
# these need to be set on child instance
#regex = Regexp.new(string)
#on_message_callback = block
end
def exec(message)
args = #regex.match(message).captures
#on_message_callback.call(args)
end
end
# somewhere else in the code, I find the class that I need...
MainAppModule.registered_extensions.each do |child|
puts child.regex.inspect # this is nil and I dont want it to be
if message =~ child.regex
return child.exec(message)
end
end
How can I design this so that the #regex will be set so I can access it within the loop?
I finally found a solution that works, and I have added now the whole code that is executable. Just store the code e.g. in file callexample.rb and call it by ruby callexample.rb
The main difference of my solution to the question is that the call to on_message now creates the instance with the relevant arguments and registers the created instance. Therefore I have deleted the method inherited because I don't need it any more.
I have added some puts statements to demonstrate in which order the code works.
class MainAppModule ## Added class
##registered_extensions = []
def self.registered_extensions; ##registered_extensions; end
end
class ExtensionBase
attr_reader :regex
def self.on_message(string, &block)
MainAppModule.registered_extensions << self.new(string, block)
end
def initialize(string, block)
#regex = Regexp.new(string)
#on_message_callback = block
end
def exec(message)
args = #regex.match(message).captures
#on_message_callback.call(args)
end
end
class MyExtension < ExtensionBase
on_message '/join (.+)' do |username|
# this will be a callback function used later
puts "Callback of #{self} called."
"returnvalue"
end
end
# somewhere else in the code, I find the class that I need...
MainAppModule.registered_extensions.each do |child|
puts "Value of regex: #{child.regex}" # this is no more nil
message = '/join something'
if message =~ child.regex
puts "On match evalue 'child.exec(message)' to: #{child.exec(message)}"
end
end

Ruby: How to hook a callback through inheritance

I've got some troubles with Ruby about callbacks (and inheritance). Here is my code:
class Lmao
def initialize
#str = "HAHAHAHAHAHHAHAHAH"
#before_laughing = []
end
def self.inherited(base)
base.extend(Callbacks)
end
def laughing
#before_laughing.each {|method| send(method) }
#str
end
end
module Callbacks
def before_laughing(*methods)
#before_laughing = methods
end
end
class Lol < Lmao
before_laughing :downcase_please
def downcase_please
#str.downcase!
end
end
a = Lol.new
a.laughing # => "HAHAHAHAHAHHAHAHAH"
And as you can see, my before laughing callback don't work... because the array #before_laughing is empty. I believe this can be fixed by editing the way I save *methods into an Lol's instance method (from inside Callbacks). But I don't really see how...
If you know the solution, thanks for your light!
Thanks to Mon_Ouie, the solution is:
class Lmao
def initialize
#str = "HAHAHAHAHAHHAHAHAH"
end
def self.inherited(base)
base.extend(Callbacks)
end
def laughing
self.class.callbacks_before_laughing.each {|method| send(method) }
#str
end
end
module Callbacks
def before_laughing(*methods)
#before_laughing = methods
end
def callbacks_before_laughing
#before_laughing
end
end
class Lol < Lmao
before_laughing :downcase_please
def downcase_please
#str.downcase!
end
end
Pretty awesome.
There are two different instance variables called #before_laughing in your code: one is an instance variable of instances of the Lmao class, which gets initialized to [] (i.e. an empty Array) in Lmao's initialize instance methods and gets read in Lmao's laughing instance method. However, since the only place this instance variable gets written to is the initializer, it will always be an empty Array.
The other instance variable is an instance variable of the Lol class object itself, which gets set to the Array [:downcase_please] inside of the before_laughing method. This one, however, never gets read.

Resources