Extract Custom object from ruby collection - ruby

I have a custom object, very simple jsut to try and figure out how ruby works.
class SomeObject
def initialize(name)
#myName = name
end
def sayHello
puts 'Hello ' + #myName
end
end
I'm then running a search using chef, and creating several of these objects and adding them to a collection : collection = [] and then collection << myObject where myObject is myObject = SomeObject.new('someName')
I'm them trying to iterate over this collection, get the object and call sayHello.
collection.each do |i|
p "Something...."
p i.name #fails
#i.sayHello # fails
end
Can anyone tell me where I'm going wrong or how I might achieve this? Thanks.
Edit: If I print 'i' to the screen I get
<#::SomeObject:0x00000005546a50 #myName="some-name">
So I'm sure its being created and is in the collection, i jsut can't get the thing out :D

Your instance variable is named #myName not #name, additionally you need to allow your instance variable to be read publicly using the attr_reader directive:
class SomeObject
attr_reader :myName
def initialize(name)
#myName = name
end
def sayHello
puts 'Hello ' + #myName
end
end
collection = [ SomeObject.new('Hunter') ]
collection.each do |i|
puts i.myName # output= Hunter
i.sayHello() # output= Hello Hunter
end

Related

How do I pull a name from a class in an Array?

Okay, this is a little hard to explain but I will try (For starters I am only just learning to code so it may be something super simple I'm missing..)
I created a few classes, I put a name in those classes, I put them in an array, I then chose one at random and try to puts the name, and it outputs blank.
Am I doing this all completely wrong? I've been learning ruby for about 3 months now so I'm sure there is a lot I don't know.
class A
attr :name
def set_name
#name = "Aaa"
end
def get_name
return #name
end
end
class B
attr :name
def set_name
#name = "Bbb"
end
def get_name
return #name
end
end
class C
attr :name
def set_name
#name = "Ccc"
end
def get_name
return #name
end
end
name_a = A.new
name_b = B.new
name_c = C.new
which_name = Array.new
which_name[0] = name_a
which_name[1] = name_b
which_name[2] = name_c
roll = rand(max 3)
puts which_name[roll].get_name
I then chose one at random and try to puts the name, and it outputs
blank.
You never called the #set_name method in your code. You can add this:
name_a.set_name
name_b.set_name
name_c.set_name
Also, you probably want to look into #attr_accessor.

Ruby class: handle any not implemented method with yaml

I want to create a special settings class Settings. The class should be able to handle cases when a user types something like Settings.new.method_1.method_2.method_3 and it's translated to something like:
result = nil
if ConfigurationSettings['method_1'].present?
result = ConfigurationSettings['method_1']
if result['method_2'].present?
result = result['method_2']
...
end
return result
Of course, I'll make it more flexible later so it can have more than 2/3 "methods".
I guess this is the issue you are facing:
class Settings
def abc
puts "abc"
end
def xyz
puts "xyz"
end
end
s = Settings.new
s.abc
#abc
# => nil
s.xyz
#xyz
# => nil
s.abc.xyz
#abc
#NoMethodError: undefined method `xyz' for nil:NilClass
The issue here is s.abc is returning nil and xyz is called over nil. What you are trying to achieve is called Method Chaining. Now, xyz needs an Settings object. Simplest thing to do here is:
class Settings2
def abc
puts "abc"
self
end
def xyz
puts "xyz"
self
end
end
s2 = Settings2.new
s2.abc.xyz
#abc
#xyz
method_missing is available for your use and can be used to help you solve this problem. Coupling this with method chaining and you're good to go. For example:
class Settings
def method_missing(meth)
puts "Missing #{meth}"
self
end
def test
puts "Test"
self
end
end
a = Settings.new
a.test
a.test.b
a.b.test
The trouble with the other answers is all the methods return "self" so if you want to access a nested value...
final_value = Settings.new.method_1.method_2.method_3
You're just going to get the whole settings hash instead.
Try this instead...
class Settings
class SubSettings
def initialize(sub_setting)
#sub_setting = sub_setting
end
def method_missing(method, *arguments, &block)
if #sub_setting[method].is_a?(Hash)
SubSettings.new #sub_setting[method]
else
#sub_setting[method]
end
end
def answer
#sub_setting
end
end
def initialize
#settings = ConfigurationSettings
end
def method_missing(method, *arguments, &block)
SubSettings.new #settings[method]
end
end
ConfigurationSettings = {level1a: {level2a: {level3a: "hello", level3b: "goodbye"}, level2b: {level3b: "howdy"}}}
result = Settings.new.level1a.level2a.level3b
p result
=> "goodbye"
What this does is take the initial method and takes the associated sub-hash of the ConfigurationSettings hash and stored it into a new object of class SubSettings. It applies the next method and if the result is another sub-hash it iterates to create another SubSettings, etc. It only returns the actual result when it no longer sees hashes.

Ruby Object name to string

I have a strange need that I can't find a good solution to.
I've got a method that I will pass either an object, hash, or array to. And I want to be able to get the name of that object, hash, or array that i'm passing.
Here is an example:
#user = User.find(5)
log_info(#user)
def log_info(obj)
Rails.logger.debug(obj.to_s)
Rails.logger.debug(obj.inspect)
end
That would log something like:
#user
{"active"=>true, "address1"=>"something", "address2"=>"", "city"=>"somewhere"}
This would just prevent me from having to do this:
#user = User.find(5)
log_info("#user", #user)
def log_info(heading, obj)
Rails.logger.debug(heading)
Rails.logger.debug(obj.inspect)
end
Any ideas on how to accomplish this?
You can do that with a little hackery - i'll just leave this here:
class Reference
def initialize(var_name, vars)
#var_name = var_name
#getter = eval "lambda { #{var_name} }", vars
end
def name
#var_name
end
def value
#getter.call
end
end
def log_info(ref)
Rails.logger.debug(ref.name.to_s)
Rails.logger.debug(ref.value.inspect)
end
def ref(&block)
Reference.new(block.call, block.binding)
end
#user = "something";
log_info(ref{:#user}) # -> #user - "something"
If your case only requires to work with instance variables, you could do something like this:
def log_info(obj)
heading = instance_variables.detect {|name| instance_variable_get(name).equal?(obj) }
Rails.logger.debug(heading)
Rails.logger.debug(obj.inspect)
end

Ruby - Calling a method from a child object

I'm new to Ruby and trying to determine how I can call a class from a child object. Something like the below; however when I try it, I get an error saying "undefined local variable or method `me'"
class my_object < Object
attr_accessor :me
def initialize(attributes ={})
end
def setvalue(passed_value)
#passed_value = passed_value.to_s
end
def search(passed_value)
#passed_value.include?(passed_value)
end
end
def getMe
me_too = my_object.new
me_too.me = "test"
me_too.me.search("test")
end
end
instance.class
will give you a reference to the class
This works:
But your code had multiple errors.
class MY
attr_accessor :me
def initialize(attributes ={})
end
def setvalue(passed_value)
passed_value = passed_value.to_s
end
def search(passed_value)
passed_value.include?(passed_value)
end
def getMe
me_too = MY.new
me_too.me = "test"
me_too.search("test")
end
end
my = MY.new
my.getMe
You don't need to explicity extend Object, everything extends Object in ruby.
Your class name needs to start with a capital letter.
class MyObject
attr_accessor :me
end
me_too = MyObject.new
me_too.me = "test"
in console
me_too => #<MyObject:0x106b2e420 #me="test">
Check out some introductory ruby tutorials maybe http://ruby.learncodethehardway.org/

Overriding instance variable array's operators in Ruby

Sorry for the poor title, I don't really know what to call this.
I have something like this in Ruby:
class Test
def initialize
#my_array = []
end
attr_accessor :my_array
end
test = Test.new
test.my_array << "Hello, World!"
For the #my_array instance variable, I want to override the << operator so that I can first process whatever is being inserted to it. I've tried #my_array.<<(value) as a method in the class, but it didn't work.
I think you're looking for this:
class Test
def initialize
#myarray = []
class << #myarray
def <<(val)
puts "adding #{val}" # or whatever it is you want to do first
super(val)
end
end
end
attr_accessor :myarray
end
There's a good article about this and related topics at Understanding Ruby Singleton Classes.
I'm not sure that's actually something you can do directly.
You can try creating a derived class from Array, implementing your functionality, like:
class MyCustomArray < Array
def initialize &process_append
#process_append = &process_append
end
def << value
raise MyCustomArrayError unless #process_append.call value
super.<< value
end
end
class Test
def initialize
#my_array = MyCustomArray.new
end
attr_accessor :my_array
end
Here you go...
$ cat ra1.rb
class Aa < Array
def << a
puts 'I HAVE THE CONTROL!!'
super a
end
end
class Test
def initialize
#my_array = Aa.new
end
attr_accessor :my_array
end
test = Test.new
test.my_array << "Hello, World!"
puts test.my_array.inspect
$ ruby ra1.rb
I HAVE THE CONTROL!!
["Hello, World!"]
$
a = []
a.instance_eval("alias old_add <<; def << value; puts value; old_add(value); end")
Very hackish, and off the top of my head ...
Just change 'puts value' with whatever preprocessing you want to do.
You can extend the metaclass of any individual object, without having to create a whole new class:
>> i = []
=> []
>> class << i
>> def <<(obj)
>> puts "Adding "+obj.to_s
>> super
>> end
>> end
=> nil
>> i << "foo"
Adding foo
=> ["foo"]
i extend the class, creating a method which provides access to the instance variable.
class KeywordBid
def override_ignore_price(ignore_price)
#ignorePrice = ignore_price
end
end

Resources