I am very new to ruby. I am facing issue in getting the variable value in self.method
My ruby class/script look like this:
class A1
def initialize
#myUtil = MyUtil.new log
#test_hash = #myUtil.loadPropertiesFile(File.dirname(__FILE__) + '/my-tests.properties')
end
def self.testCases
tests = {}
#test_hash.each do |k, v|
puts "#{k}"
end
tests
end
def launch test, testbed, h = {}
#test_hash.each do |k, v|
puts "#{k}"
end
end
end
I am able to print value in #test_hash in launch method but not in self.testCases. Where I am making the mistake?
I see a few errors in your code.
In your initialize method, you created a global variable $test_hash, anytime you put a $ in front of a variable, it becomes available everything. That is not something you want to do in this case. An instance variable would work best for you in this case.
Your testCases method is a class method, which means you can call it without creating a new instance of the class, ie A1.new. So you call the method like A1.testCases (Ruby uses snake case for method names, test_cases, just fyi). You initializes the test_hash variable in the initialize method, which does not automatically gets call until you create a new instance of the class. Therefore, test_hash does not exist when you simply run 'A1.testCases`.
for the line puts "#{k}" is not good practice. puts stands for put string, and it will automatically convert the variable into a string. You should use puts k. the #{} is meant for string interpolation. Such as "Hi, my name is #{name}, and I am #{age} years old."
Here's how I would do this. I replaced the test_hash with a simple hash for testing purposes.
class A1
def initialize
#test_hash = {a: 1, b: 2, c: 3, d: 4, e: 5}
end
def testCases
#test_hash.each do |k, v|
puts k
end
end
end
Now, you create a new instance of A1 and call the testCases method (now an instance method, instead of a class method)
A1.new.testCases
The hard part is to understand, that in Ruby classes are also object. So a1 = A1.new is an object and A1 is also an object.
By using # inside initialize, you create an instance variable belonging to a1 = A1.new object.
By using # inside self.testCases method, you create instance variable belonging to A1 object.
Related
I am trying to place 3 values into each index of an array. The values are for the class, assignment, and grade. They come from a class object called Grade_Log.
I am running into an issue with the output.
class Grade_Log
attr_accessor :which_class, :assignment_type, :grade
def initialize(which_class, assignment_type, grade)
#which_class = which_class
#assignment_type = assignment_type
#grade = grade
end
end
#values are assigned to add_class, add_assignment, and add_grade
grade_index[grade_index_tally] = Grade_Log.new(add_class,add_assignment,add_grade)
puts grade_index[grade_index_tally]
I would like for it to output, for example, "PHYSICS, HOMEWORK, 95", but instead I am getting the following. #<Grade_Log:0x0000000002baaa20>
If you want to be able to puts an instance of your Grade_Log class, you'll need to define to_s for your class. Right now, it's likely using the default to_s method.
I think you'd want something like this:
class Grade_Log
... # your code
def to_s
"#{which_class}, #{assignment_type}, #{grade}"
end
end
Which is basically the same thing as:
def to_s
[which_class, assignment_type, grade].join(', ')
end
When you instantiate a Grade_Log object, the initialize method is called and the parameters are assigned to attributes:
tmp = GradeLog.new("PHYSICS", "HOMEWORK", 95)
If you simply puts the variable you get the object information:
puts tmp #=> #<Grade_Log:0x007fc27213f3a8>
To access the attributes you should do
puts tmp.which_class #=> PHYSICS
puts tmp.assignment_type #=> HOMEWORK
puts tmp.grade #=> 95
A fast way to see the object content is the inspect method:
puts tmp.inspect #=> #<Grade_Log:0x007fd7e6917358 #which_class="PHYSICS", #assignment_type="HOMEWORK", #grade=95>
which is the same as using Kernel#p:
p tmp #=> #<Grade_Log:0x007fd7e6917358 #which_class="PHYSICS", #assignment_type="HOMEWORK", #grade=95>
Another option is to access the instance variables, Object.html#instance_variables and Object.html#instance_variable_get:
tmp.instance_variables.map { |v| tmp.instance_variable_get(v) } #=> ["PHYSICS", "HOMEWORK", 95]
Or define a custom method inside your class, to get the array of values, for example (no need to edit the method when a new attribute is added):
def attributes_values
instance_variables.map { |v| instance_variable_get(v) }
end
So you can call just
tmp.attributes_values #=> ["PHYSICS", "HOMEWORK", 95]
Finally, if you want format the output as a string you could define a to_s method to override the default Object#to_s method, to call puts tmp.
Looking at this instance_eval example:
class KlassWithSecret
def initialize
#secret = 99
end
def get
#secret
end
end
k = KlassWithSecret.new
k.instance_eval { #secret }
print k.get
I added a get method to KlassWithSecret.
Here's the results of running the program:
>ruby InstanceEvalTest.rb
99
So, does instance_eval here somehow call the initialize method?
I think that I understand this method a bit from reading this helpful post. But I'm still in the dark.
The initialize method is automatically called by Ruby after the new method is called. instance_eval runs the block you supply in the context of the object. This means it has access to anything a normal line of code in the KlassWithSecret class would have.
#secret is an instance variable, meaning that it belongs to an instance of KlassWithSecret. Because we're evaluating { #secret } in the context of a KlassWithSecret instance, we can access #secret.
k.instance_eval gives you access to all of the instance variables (here just #secret) and all private methods (if there were any). It executes the code in the block, which in this case returns 99, the value of #secret. Then print k.get prints that value and returns nil.
If the block had been { #secret = 'cat' }, k.instance_val would have changed the value of #secret (and returned the new value).
When using instance_eval, class_eval, class < self and other metaprogramming constructs, you mind find it helpful to track the value of self using puts statements. For example:
k = KlassWithSecret.new #=> #<KlassWithSecret:0x00000101897810 #secret=99>
self #=> main
k.instance_eval { puts "self=#{self}"; #secret }
"self=#<KlassWithSecret:0x00000101897810>"
#=> 99
- EDIT, SOLVED -
Ended up creating a method Object#rec to accomplish what I needed, this is the result:
#$l stores the last object on which Object#rec was called
$l=nil;class Object;def rec;$l=self;end;end
class String
attr_accessor :ref
alias_method :old_reverse, :reverse
def reverse
self.rec.old_reverse
end
def my_method
$l.ref + ' ' + self
end
end
a = "Hello"
b = "dlroW" ; b.ref = a
p b.reverse.my_method #=> Hello World
If anyone has a better way the question is still open.
- EDIT, SOLVED -
The problem:
I have a situation similar to this:
obj.method1.method2
where method1 returns something other than obj and I need method2 to access obj again as it holds a reference I need.
For example:
class String
attr_accessor :ref
def my_method(b)
b.ref + ' ' + self
end
end
a = "Hello"
b = "dlroW" ; b.ref = a
#I want my_method to access 'b.ref' without having to pass 'b'
p b.reverse.my_method(b) #=> Hello World
Alternative:
I know I could avoid having to pass b again if I used obj.my_method and my_method did both reversing(for the example) and accessing the reference, or like commented by the Tin Man have method1 change obj but return the original obj, but what I want is to know if it's possible or not to accomplish the above.
Thanks in advance.
Sounds kind of like you're looking for Object.tap:
Yields x to the block, and then returns x. The primary purpose of this method is to “tap into” a method chain, in order to perform operations on intermediate results within the chain.
For your example, you might be able to use String's reverse! inside the tap to manipulate the object. For your application, manipulate the object as you desire inside tap, then the object will be passed on to your following method.
If I run this file as "ruby x.rb":
class X
end
x = X.new
What is the thing that is calling "X.new"?
Is it an object/process/etc?
Everything in Ruby occurs in the context of some object. The object at the top level is called "main". It's basically an instance of Object with the special property that any methods defined there are added as instance methods of Object (so they're available everywhere).
So we can make a script consisting entirely of:
puts object_id
#a = 'Look, I have instance variables!'
puts #a
and it will print "105640" and "Look, I have instance variables!".
It's not something you generally need to concern yourself with, but it is there.
The top-level caller is an object main, which is of class Object.
Try this ruby program:
p self
p self.class
It's the X class. You're invoking the method "new" that creates an object of class X. So, if you run this text as a script, Ruby:
creates a new class X which is a subclass of Object, and which automatically (as a subclass of Object) inherits some methods, of which new is one.
sets up a name x
calls the new method on that new class X, creating an X instance object; x gets a reference to that object.
It's the ruby interpreter running the line
x = X.new
As with many scripting languages, the script is interpreted from top to bottom rather than having a standard entry point method like most compiled languages.
As Charlie Martin said, X.new is a call to the constructor on the X class, which returns an object of type X, stored in variable x.
Based on your title, I think you're looking for a bit more. Ruby has no need for a main, it executes code in the order that it sees it. So dependencies must be included before they are called.
So your main is any procedural-style code that is written outside of a class or module definition.
main is the object in the context of which the top level code is executed. Which means that self at the top level refers to the main object:
$ ruby -e 'p self'
main
And that ruby follows the main's method lookup chain to determine which method to call:
$ ruby -e 'p singleton_class.ancestors'
[#<Class:#<Object:0x00007f9e9fdee230>>, Object, Kernel, BasicObject]
There could be more, but that's what you get from the get-go.
main itself is an instance of Object:
$ ruby -e 'p self.class'
Object
It has a singleton class with 2 methods (a method and an alias to be more precise):
$ ruby -e 'p singleton_class.instance_methods(false)'
[:inspect, :to_s]
$ ruby -e 'p singleton_methods'
[:inspect, :to_s]
It's defined here.
As you can see its to_s method returns "main" (overrides the Object's behavior), which is what you get when you do p self.
You can think that the code you execute is put into a main's method, after which the method is called. Along the lines of:
main = Object.new
class Object
def main.go
<your code here>
end
end
main.go
That is a rough idea. Let me justify it in a couple of steps.
In Ruby you can actually nest methods, but every time you call the outer method, the inner one gets defined/redefined. More importantly, it's defined as an instance method of the enclosing class:
class A
def m
def m2; end
end
end
A.new.m
p A.instance_methods(false) # [:m2, :m]
The same happens here, but the enclosing class in this case is the singleton class of A:
class A
class << self
def m
def m2; end
end
end
end
A.m
p A.singleton_class.instance_methods(false) # [:m2, :m]
And what if we use the def self.<name> notation?
class A
def self.m
def m2; end
end
end
A.m
p A.singleton_class.instance_methods(false) # [:m]
p A.instance_methods(false) # [:m2]
So, self. affects only m, m2 becomes an instance method of A.
Actually, instead of self there can be some random object:
o = Object.new
A = Class.new do
def o.m
def m2; end
end
end
o.m
p o.singleton_class.instance_methods(false) # [:m]
p A.instance_methods(false) # [:m2]
I had to use Class.new because with class o wouldn't be visible inside the class definition.
Or actually I hadn't:
class A
o = Object.new
def o.m
def m2; end
end
o.m
p o.singleton_class.instance_methods(false) # [:m]
p A.instance_methods(false) # [:m2]
end
But let's ignore this branch of thought.
A couple of changes and you get this:
main = Object.new
Object.class_eval do
def main.go
#a = 1
def m2
puts #a
end
m2 # 1
end
end
main.go
p Object.instance_methods(false) # [:m2]
p main.instance_variables # [:#a]
I had to use class_eval for it to not complain that I'm trying to redefine the Object constant.
You can also add:
def main.to_s
"main"
end
main.instance_eval { alias inspect to_s }
for completeness.
Another way is to use global variables:
$main = Object.new
class Object
def $main.go
#a = 1
def m2
puts #a
end
m2 # 1
end
end
$main.go
p Object.instance_methods(false) # [:m2]
p $main.instance_variables # [:#a]
Of course variables main/$main and the go method don't exist. But no more flaws come to mind when I think about this idea. The idea that it works as if your code is put into a main's method and executed by running the method.
Also this kind of explains why methods defined at the top level are visible everywhere:
a.rb:
f
$ ruby -e 'def f; puts "f"; end; require "./a"'
f
Because they become instance methods of Object.
And you can use instance variables, which are instance variables of the main object.
UPD I noticed that you can't define constants (in the usualy way), classes and modules in main.go. So the abstraction appears to be leaky. I might try to amend it:
Object.class_eval do
<your constants, classes, modules, methods>
def main.go
<the rest of the code>
end
end
But at this point I'd rather say, that at the top level self points to the main object, and the current class reference to the Object class. More on class references here.
Previously, I asked about a clever way to execute a method on a given condition "Ruby a clever way to execute a function on a condition."
The solutions and response time was great, though, upon implementation, having a hash of lambdas gets ugly quite quickly. So I started experimenting.
The following code works:
def a()
puts "hello world"
end
some_hash = { 0 => a() }
some_hash[0]
But if I wrap this in a class it stops working:
class A
#a = { 0 => a()}
def a()
puts "hello world"
end
def b()
#a[0]
end
end
d = A.new()
d.b()
I can't see why it should stop working, can anyone suggest how to make it work?
that code doesn't work. it executes a at the time it is added to the hash, not when it is retrieved from the hash (try it in irb).
It doesn't work in the class because there is no a method defined on the class (you eventually define a method a on the instance.
Try actually using lambdas like
{0 => lambda { puts "hello world" }}
instead
First of all, you are not putting a lambda in the hash. You're putting the result of calling a() in the current context.
Given this information, consider what the code in your class means. The context of a class definition is the class. So you define an instance method called a, and assign a class instance variable to the a hash containing the result of calling a in the current context. The current context is the class A, and class A does not have a class method called a, so you're trying to put the result of a nonexistent method there. Then in the instance method b, you try to access an instance variable called #a -- but there isn't one. The #a defined in the class context belongs to the class itself, not any particular instance.
So first of all, if you want a lambda, you need to make a lambda. Second, you need to be clear about the difference between a class and an instance of that class.
If you want to make a list of method names to be called on certain conditions, you can do it like this:
class A
def self.conditions() { 0 => :a } end
def a
puts "Hello!"
end
def b(arg)
send self.class.conditions[arg]
end
end
This defines the conditions hash as a method of the class (making it easy to access), and the hash merely contains the name of the method to call rather than a lambda or anything like that. So when you call b(0), it sends itself the message contained in A.conditions[0], which is a.
If you really just want to pretty this sort of thing up,
why not wrap all your methods in a class like so:
# a container to store all your methods you want to use a hash to access
class MethodHash
alias [] send
def one
puts "I'm one"
end
def two
puts "I'm two"
end
end
x = MethodHash.new
x[:one] # prints "I'm one"
x.two # prints "I'm one"
or, to use your example:
# a general purpose object that transforms a hash into calls on methods of some given object
class DelegateHash
def initialize(target, method_hash)
#target = target
#method_hash = method_hash.dup
end
def [](k)
#target.send(#method_hash[k])
end
end
class A
def initialize
#a = DelegateHash.new(self, { 0 => :a })
end
def a()
puts "hello world"
end
def b()
#a[0]
end
end
x = A.new
x.a #=> prints "hello world"
x.b #=> prints "hello world"
One other basic error that you made is that you initialized #a outside of any instance method -
just bare inside of the definition of A. This is a big time no-no, because it just doesn't work.
Remember, in ruby, everything is an object, including classes, and the # prefix means the instance
variable of whatever object is currently self. Inside an instance method definitions, self is an instance
of the class. But outside of that, just inside the class definition, self is the class object - so you defined
an instance variable named #a for the class object A, which none of the instances of A can get to directly.
Ruby does have a reason for this behaviour (class instance variables can be really handy if you know what
you're doing), but this is a more advanced technique.
In short, only initialize instance variables in the initialize method.
table = {
:a => 'test',
:b => 12,
:c => lambda { "Hallo" },
:d => def print(); "Hallo in test"; end
}
puts table[:a]
puts table[:b]
puts table[:c].call
puts table[:d].send( :print )
Well, the first line in your class calls a method that doesn't exist yet. It won't even exist after the whole class is loaded though, since that would be a call to the class method and you've only defined instance methods.
Also keep in mind that {0 => a()} will call the method a(), not create a reference to the method a(). If you wanted to put a function in there that doesn't get evaluated until later, you'd have to use some kind of Lambda.
I am pretty new to using callbacks in Ruby and this is how I explained it to myself using an example:
require 'logger'
log = Logger.new('/var/tmp/log.out')
def callit(severity, msg, myproc)
myproc.call(sev, msg)
end
lookup_severity = {}
lookup_severity['info'] = Proc.new { |x| log.info(x) }
lookup_severity['debug'] = Proc.new { |x| log.debug(x) }
logit = Proc.new { |x,y| lookup_sev[x].call(y) }
callit('info', "check4", logit)
callit('debug', "check5", logit)
a = ->(string="No string passed") do
puts string
end
some_hash = { 0 => a }
some_hash[0].call("Hello World")
some_hash[0][]