I'm learning Ruby and made a class to help:
class WhatImDoing
def initialize
puts "not doing anything"
end
end
with the output of:
not doing anything
#<WhatImDoing:0xb74b14e8>
I'm curious, what is the second line all about? Is it a reference location for the WhatImDoing object I created? Can I access objects through this location(like a pointer or something)? Etc... Just trying to get a better understanding of Ruby, in general.
Thanks.
The second line is the output of irb, showing the return value of the last statement.
If you set something equal to that value:
> class WhatImDoing
def initialize
puts "not doing anything"
end
def ohai
puts "Ohai"
end
end
> tmp = WhatImDoing.new
=> #<WhatImDoing:0x5cd5a2a9>
You could use it:
> tmp.ohai
Ohai
If you had a custom to_s it would show that instead:
> class WhatImDoing
def to_s
"#{super} kthxbai"
end
endt
> tmp = WhatImDoing.new
=> #<WhatImDoing:0x3e389405> kthxbai
I'm assuming that was the output of irb. Irb tried to print your object, i.e. convert it to a string. Since you didn't provide a custom to_s ("to string") method, your object inherited this one:
http://ruby-doc.org/core-1.9.3/Object.html#method-i-to_s
Returns a string representing obj. The default to_s prints the object’s class and an encoding of the object id. As a special case, the top-level object that is the initial execution context of Ruby programs returns “main.”
Further digging into the source code reveals that the hexadecimal number is, indeed, the memory address occupied by that object instance. There isn't really anything fancy you can do with that information, in Ruby. It's just a convenient way to generate an unique identifier for an object instance.
Yes, it is reference to the object you are creating. Yes, you can access that object.
Related
Given this script
def hash
puts "why?"
end
x = {}
x[[1,2]] = 42
It outputs the following
why?
/tmp/a.rb:6:in `hash': no implicit conversion of nil into Integer (TypeError)
from /tmp/a.rb:6:in `<main>'
It seems that the hash function defned in the script is overriding Array#hash in that case. Since the return value of my hash method is nil and not an Integer, it throws an exception. The following script seems to confirm this
puts [1,2,3].hash
def hash
puts "why?"
end
puts [1,2,3].hash
The output is
-4165381473644269435
why?
/tmp/b.rb:6:in `hash': no implicit conversion of nil into Integer (TypeError)
from /tmp/b.rb:6:in `<main>'
I tried looking into the Ruby source code but could not figure out why this happens. Is this behavior documented?
You're not overriding Array#hash, you're shadowing Kernel#hash by creating Object#hash:
puts method(:hash)
def hash
puts "why?"
end
puts method(:hash)
That prints:
#<Method: Object(Kernel)#hash>
#<Method: Object#hash>
Fix it so we can see more:
def hash
puts "why?"
super
end
x = {}
x[[1,2]] = 42
Now the output is:
why?
why?
And no error. Try it with x[[1,2,3,4,5,6,7]] = 42 and you'll instead see why? printed seven times. Once for each array element, since the array's hash method uses the hashes of its elements. And Integer#hash doesn't exist, it inherits its hash method from Object/Kernel, so yours gets used.
This is due to a kind of hack in Ruby top level. Have you ever wondered how this works?
def foo
end
p self
foo
class Bar
def test
p self
foo
end
end
Bar.new.test # no error
How are two totally different objects (main and a Bar) able to call foo like it's a private method call? The reason is because... it is a private method call.
When you define a method at the top level of your Ruby script, it gets included (via Object) in every object. That's why you can call top-level methods like they are global functions.
But why does this break only hash and not other common methods? def to_s;end won't break to_s, for example. The reason is because hash is recursive: most* class implementations ultimately call down to Object#hash for their implementations. By redefining that base case, you break it globally. For other methods like to_s you won't see a global change because it's way up the inheritance chain and doesn't get invoked.
* the only objects this doesn't break are a few literals that probably have hard-coded hash values e.g. [] {} "" true etc.
Reading Understanding Computation from O'Reilly I bumped into an issue with the examples
(I am completely new to Ruby and the introduction to the book is the only Ruby know-how I got)
On page #44 there is the example
class Number
def evaluate(environment)
self
end
end
Evaluating Number.new(23).evaluate({}) according to the book should give 23 but I am getting an error that Number class has zero params and I am passing one
Changing the class definition to class Number < Struct(:val) works but nothing happens
After I changed to code to
class Number < Struct.new(:value)
def evaluate(environment)
environment[self] = value
self.value = value
value
end
def to_s
print(self)
end
end
this seems to work but I just can't figure out why the author would start publishing non-working code out of the blue? Am I missing something?
It would be nice if some one that has read the book can help
Another quick question, how can I use irb to evaluate a file with Ruby classes but keep the interpreter open so I can continue.. When I do irb test.rb it does the evaluation but then exits..
Thanks
You need to evaluate the code blocks in previous pages in irb. To make 'Number.new(23).evaluate({})' work, copy and paste the code below to irb.
In ruby, you can open up the class definition of an existing class and do things like add methods or change class behavior. Google 'open classes' for more details.
class Number < Struct.new(:value)
end
class Number
def to_s
value.to_s
end
def inspect
"«#{self}»"
end
end
class Number
def evaluate(environment)
self
end
end
To evaluate a file in irb, use 'require'.
irb > require 'number' # evaluates ./number.rb
The initialize method is called when an object is constructed using the class method new, so the arity of both must match, the default initialize takes no arguments which is why you get the error.
class Number
def initalize(number)
# ...
end
end
Number.new(1)
The code as you have in your question is incorrect.
I'm trying to implement a funky version of method chaining. Returning the instance of the class after each function call is easy, you just do
def chainable_method
some_code()
self
end
My idea is that the methods you can call depend on the previous method call. I'm trying to achieve this by returning an object belonging to the containing object. The contained object will have a few special methods, and then implement method_missing to return the containing object's instance.
Edit: The child object has some state associated with it that should be in itself, and not the parent. It might not have been clear previously as to why I need a whole instance for just method calls.
super is irrelevant in this case because the contained object doesn't inherit from the containing object, and I wouldn't want to call the containing object's methods on the contained object anyway - I want to call the containing object's methods on the containing object itself. I want the containing object, not the containing object class.
Not sure if this is possible.
Edit: reworded everything to use "containing/contained object" instead of the completely incorrect parent/child object.
Also, I'm using 1.9.3, if that matters. Version isn't important, I can change if needed.
My explanation was probably unclear. Here's the code:
class AliasableString
def initialize(string)
#string = string
end
def as(aka)
#aka = aka
end
def has_aka?
!#aka.nil?
end
# alias is a reserved word
def aka
#aka
end
def to_s
#string + (self.has_aka? ? (" as " + #aka) : "")
end
end
class Query
def initialize
#select_statements = Array.new
end
def select(statement)
select_statement = AliasableString.new(statement)
#select_statements.push(select_statement)
select_statement
end
def print
if #select_statements.size != 0
puts "select"
#select_statements.each_with_index {| select, i|
puts select
}
end
end
end
# Example usage
q0 = Query.new
q0.select("This is a select statement")
.select("Here's another one")
.as("But this one has an alias")
.select("This should be passed on to the parent!")
q0.print
I haven't yet fully implemented print. AliasableString needs to have #string and #aka separate so I can pull them apart later.
First of all, it doesn't matter what class of object is contained within a Query instance. All of the syntax shown on your 'example usage' section is appropriately defined in Query. The only requirement of the objects contained within a query instance is that they respond to as (or some similar method). What you have here is something like a state machine, but the only state that really matters is that some object occupies the last position in the select_statements array. Here's how I would build this (again, based mostly on your example at the end, I'm afraid I can't quite follow your initial explanation):
class Query
# ... initialize, etc.
def select(statement, statement_class = AliasableString)
select_statements << statement_class.new(statement)
self
end
def as(aka)
# this will only ever be used on the most recent statement added
statement_to_alias = select_statements.last
# throw an error if select_statements is empty (i.e., :last returns nil)
raise 'You must add a statement first' unless statement_to_alias
# forward the message on to the statement
statement_to_alias.as(aka)
# return the query object again to permit further chaining
self
end
end
AliasableString doesn't need to know a thing about Query; all it needs to do is respond appropriately to as.
Maybe this is a stupid idea... I am new to Ruby (and to OOP, so I still dont really know what I am doing most of the time), and I thought of a small, fun project to build, and I am struggling with some concepts.
What I am building is basically a string manipulator. I am building a module with extra methods, and then including that on the String class.
My module has several methods that manipulate the strings in different ways, mostly replacing words, and then return the modified string.
What I want to do in order to make the string manipulation more 'spontaneous' and natural, is to create a "main" method (the one I will be calling from the strings), that randomly selects one of the string manipulation methods, and then returns the string (and then can be called again to apply several manipulations in one go)
How can I do this, or something similar? Hope I explained myself
Thanks
O.
Here's the random manipulation module, as you described it. something_random is the main method:
module RandomStringManipulation
def something_random
methods = RandomStringManipulation.instance_methods
methods -= [:something_random]
send methods.sample # Ruby >= 1.9 required. See below for Ruby 1.8.
end
def foo
self + "foo"
end
def bar
self + "bar"
end
end
Mix it into String:
class String
include RandomStringManipulation
end
Now we can create an empty string, and then do something random to it a few times, printing it out each time:
s = ""
4.times do
s = s.something_random
p s
end
# => "foo"
# => "foobar"
# => "foobarbar"
# => "foobarbarfoo"
There are two bits that are interesting. The first is this:
methods -= [:something_random]
That removes :something_random from the array methods, preventing the *something_random* method from calling itself. The second interesting bit is this:
send methods.sample
Array.sample (Ruby >= 1.9) selects a random method. send then dispatches that method. In Ruby 1.8, do this instead:
send methods[rand(methods.size)]
If all the code that will be using your functionality is your code, I would make a new class instead of monkey-patching String. Monkey-patching leads to code that is harder to understand and share.
Anyway, given a list of mutator methods, you can easily pick one at random and use Object#send to call it:
module StringMutator
def fold() ... end
def spindle() ... end
def mutilate() ... end
end
class NiftyString
include StringMutator
def random_change()
im = StringMutator.instance_methods
self.send im[rand im.length]
end
end
i have the following
class test
hash={}
def printHash
puts hash[1]
puts hash[2]
puts hash[3]
end
end
test.new.printHash
this prints:
1
0
1
Why does this happen? how can i test whether or not i have put something in that spot of the hash? or am i missing something
You're well off the mark, but it appears to be doing something because hash is a builtin function which returns a Fixnum hashcode for the object. When you use square brackets on a Fixnum, you get the value of the specific bit. What you want to do is to create an instance variable, which starts with the sigil #. Also, you have to create instance variables within a method, so we'll use the one that's called whenever an object of the class is created, initialize:
class Test
def initialize
#hash = {}
end
def printHash
puts #hash[1]
puts #hash[2]
puts #hash[3]
end
end
Now you'll find this prints nil for all three. To test whether a hash has a value for a specific key, you can use has_key?.
Basically 'hash' is out of scope, what you are referencing in your printHash function is a different object altogether, normally it would be nil (a new unassigned object) but as Pesto points out 'hash' is a built in function - somewhat confusing this explanation.
By putting an '#' sign in front of the your variable and assigning it in the initialize method (which is called after 'new') it becomes available in the entire instance of your object.