I'm new in ruby on rails and have a little confusion on the following code
module Comment
class CommentScore < ActiveRecord::Base
self.table_name = 'comment_scores'
# Associations
belongs_to :provider_account
# Scopes
scope :by_provider_account_id, lambda { |provider_account_id| where(provider_account_id: provider_account_id) }
# Instance methods
def set
return unless self.valid?
return if unsettable?
self.positive_count = provider_account.comment.total(:positive)
self.total = provider_account.comment.total(:all)
self.score = decimal
self.save!
end
def decimal
positive_count.to_d / total.to_d
end
end
end
from my studies, I learned that if the 'self' keyword is used inside a method, it will just actually call a method like in this example, self.positive_count, calls the method 'positive_count' which in rails, means the table column named 'positive_count'.
So I got a bit confused in the 'decimal' method, it just use 'positive_count' without the self? Isn't it a local variable?
ActiveRecord will define getters and setters for each field in your model, eg. in this case you will get positive_count and positive_count= defined.
You can call the getter easily, like you are doing in your decimal method. However, to call the setter like you are in your set method, you need to use self - otherwise you will simply set a local variable in that method with the value, instead of calling the setter.
When there is such local variable as positive_count, then the form positive_count without the period and arguments will be interpreted as a local variable. If not, then it will be interpreted as a method. However, methods of the form foo= are obligatorily private.
Based on context and what methods have been defined, Ruby will try and determine if you're making a method call or reading from or assigning to a variable. Unlike other languages where local variables must be defined in advance (int total), or where variables are specified with a different syntax ($int), Ruby has a syntax that's a lot more stripped down. This can lead to some ambiguity.
If there's a method defined with a particular name, like decimal or there's a method that accepts values, such as total=, then a method call will be made when these are referenced. Otherwise it's presumed they're variables.
Use of self avoids ambiguity and forces a method call. It's often used to be sure there's no risk of creating a variable by accident.
Consider the following:
def example
total = 50
end
Is total a variable, or is there a method called total= that can be used instead? It's not clear from this short example. By default Ruby will treat that as a variable.
Now if you have a column in the database called total, this is discovered after the original model code has been loaded. At that time there was no method called total=. This method is created dynamically after the first instance of that model is instantiated. This is where you get the self-dot notation showing up:
def example
self.total = 50
end
This ensures you're assigning to the attribute and not creating a local variable by mistake.
Related
There is a class Commerce and its constructor will initialize an object named commerce. LineItem is a class with in the Commerce class. LineItem class has a method named "ssm". when this method "ssm" is invoked it will initialize an object of another class named SSM. In our problem, we need pass to the "ssm" method as a function argument in another Test class.
def autoUpdate(docNum, type, varName, value)
type = method(Commerce::LineItem:ssm)
commerce.line_item.type(varName).set(value)
end
In the place of the function parameter 'type', it should be replaced by different method names from the class LineItem. However the above function autoUpdate throws an error. How to pass child class methods as function parameters in another class.
I think what you're doing is probably a mistake and a terrible design, but for your specific question if you actually want a method object, I think you want:
type_method = Commerce::LineItem.instance_method(:ssm)
You could then call it by:
bound_type_method = comerce.line_item.bind(type_method).call(varName).set(value)
But this doesn't make a lot of sense. You could also just pass the symbol, method_name = :ssm, and later call commerce.line_item.type.send(method_name, varName).set(value)
That's still kind of a mess though, this is scary code.
Also there appear to be 'child classes' involved here.
Passing methods as arguments and changing their receivers is not as easy to do in Ruby as it is in, say, Javascript, nor is it as conventional. Instead, usually when this sort of thing needs to be done, the Ruby convention is to use blocks. E.g. if you defined your auto_update method like this
def auto_update(doc_num, var_name, value)
raise ArgumentError, "Block is required." unless block_given?
line_item = yield var_name
line_item.set(value)
end
Then you might call it like this
auto_update(doc_num, var_name, value) do |var_name|
commerce.line_item.ssm(var_name)
end
Granted that looks pretty silly, for a number of reasons (for instance, why not just call the contents of the block first and then pass in the result as an argument for auto_update). If you describe your design a bit more, in particular from where this auto_update method is being called and how the value for type is determined, that might help.
I would like to extend the functionality of variables in Ruby. The reason is I am working on something similar of a type system or value checker (this sounds a bit crazy but the whole idea is to long to explain, just the reason I would like to extend default variables).
I have read that in Ruby, everything is an object; so variables are objects. And Ruby is supposed to be quite liberal concerning what can be changed via meta-programming.
Is there some kind of 'Class' associated with local variables that I could extend?
I would like to associate a string-variable for each variable that holds a string representation of a type. Further I would like to intercept variable assignments and execute a method each time a new value is assigned to a variable. This is so I can check, if the new value is correct according to the type (stored as string in the Variable).
If local variables in Ruby are defined as object of a class, I can extend that class or modify it via a ruby mixin.
The workaround would be to create a new class for my Variables (and not use the build in local variables of Ruby). This class can have a value attribute, a attribute (stored as string) for the type and a get- and set-method. This way I can solve my problem, but I would like to extend the built in variables in ruby, if that is possible.
current work in progress
class Fixnum
attr_accessor :tp
#tp
def mytype ( type )
#tp = type
end
def typecheck
#call typechecker
puts "checked"
end
end
Test Code:
a = 3
a.mytype("nat")
puts a.tp
a.typecheck
There are still two problems.
First, I think it is not possible to add a new constructor to Fixnum. Second, I would like to intercept the variable access, i.e. "b = a" calls the method 'typecheck' of a. But this would require something similar to Aspect Oriented Programming and I am not sure if this can be solved with Ruby's meta-programming facilitates.
I have read that in Ruby, everything is an object
That depends on your definition of "object" and every-"thing". "Object" can mean "entity that can be manipulated by the program" (which I will call object from now on), or "value that is a member of the object system" (which I will call Object from now on).
In Ruby, everything that can be manipulated by the program (i.e. every object) is also an Object, i.e. an instance of a class. This is unlike Java, for example, where primitives can be manipulated by the program (i.e. are objects in that sense of the word), but aren't Objects. In Ruby, this distinction doesn't exist: every object is an Object and every Object is also an object.
However, there are things in the language, which cannot be manipulated by the program and which aren't instances of a class, i.e. they are neither object s nor Objects. These are, for example, methods, variables, syntax, parameter lists, arguments lists, keywords.
Note: you can use Ruby's reflection API to give you an object that represents a method or a parameter list, but that object is only a proxy, it is not the real thing.
So, when we say "everything is an object", what we really mean is that "every object is an Object", i.e. that everything which can be manipulated by the program is also a member of the object system, or in other words, there are no values outside of the object system (unlike primitives in Java). We do not mean that everything that exists in the language can also be manipulated at runtime by the program.
so variables are objects
No, unfortunately, they are neither object s nor Objects.
This is also clearly stated in the Ruby Language Specification (emphasis added by me):
6.2 Variables
6.2.1 General description
A variable is denoted by a name, and refers to an object, which is called the value of the variable.
A variable itself is not an object.
In the book The Ruby Programming Language by Matz and David Flanagan it says on page 2:
every value is an object
Note, it doesn't say every-thing, only every value.
See also the question Is variable is object in ruby?
There are a couple things you can do. For starters, all (or very nearly all) Ruby classes (including "primitives" such as numbers) support a to_s method which returns a string representation of the object. For numbers, to_s will just return the string representation of that number (e.g., "42" for 42). The string value returned for other classes will vary. The nice thing is that you can override a class's methods via "monkey patching". Here's an extremely contrived example:
class Array
def to_s
return "An array of size #{self.size}."
end
end
a = [1, 2, 3, 4]
puts a.to_s
# => "An array of size 4."
For your other question regarding executing a method every time a variable's value is set, the way to handle this is to always interact with the variable through its accessor methods. This way you can implement custom code inside a property's getter and setter methods (or simply call another method from inside the accessor). Like this:
class MyClass
# Use the default getter for var.
attr_reader :var
def initialize
#var = 1
end
# Custom setter for var.
def var= v
#var = v
puts "var changed to #{v}"
end
end
mc = MyClass.new
mc.var = 9
# => "var chaged to 9"
You could do something like this, but it only works for globals:
$type_checked = {:$a => String, :$b => Array}
$type_checked.keys.each do |var|
trace_var(var) do |obj|
puts "hey, don't assign #{var} to a #{obj.class}" unless $type_checked[var] == obj.class
#or raise an Error
end
end
$a = 1
$a = "a"
$b = 1
#output:
#hey, don't assign $a to a Fixnum
#hey, don't assign $b to a Fixnum
But this clearly goes against the grain of the language.
I'm just learning to program and have decided to try Ruby. I'm sure this is a stupid question, but the instructor is talking about setter and getter methods, and I'm confused. Here is the example:
class Human
def noise=(noise)
#noise = noise
end
def noise
#noise
end
end
From this, the class is instantiated, and I can puts this out:
man = Human.new
man.noise=("Howdie!")
puts man.noise
This results in Howdie!
Now what confuses me is that the instructor is saying without the getter method (the 2nd of the two methods), there is no way to interact with the instance variable #noise.
But when I remove the getter method, I'm able to still access #noise, see example:
class Human
def noise=(noise)
#noise = noise
end
end
man = Human.new
puts man.noise=("Howdie!")
This works the same as when the getter method it used.
So now I'm confused. Why is the getter needed? What does the instructor mean by not being able to access the instance variable without it? Is it possible he's using an older version of Ruby?
Thanks in advance for your help.
You can interact with that instance variable from other methods belonging to that instance, even if there is no getter:
def noise=(noise)
#noise = noise
end
def last_noise
#noise
end
There doesn't need to be a getter defined with the same name as the method; the two are not linked at all. The getter is needed to "get" the value of the instance variable, but only in a short syntax.
What's happening in your example is that you're initializing a new object (Human.new), and then using a method (noise=, yes the method name contains the = symbol) that just-so-happens to define an instance variable (that is, a variable just for that instance), and then finally retrieving that instance variable with another method call.
You can actually use instance_variable_get to get the instance variable without defining any getter at all:
man = Human.new
man.noise = "Howdie"
man.instance_variable_get("#noise")
This will return "Howdie", even though there is no getter defined.
And no, I don't think he's using an older version of Ruby.
The line of code
puts man.noise=("Howdie!")
does NOT use the getter method, so the getter method does not need to be defined for it to work. That line just uses the setter method. The return value of the setter method is automatically equal to whatever is on the right-hand side of the equal sign, so "Howdie!" gets passed to puts.
The line of code
puts man.noise
DOES use the getter method, and it would not work if you remove the getter method.
Surely they both return a value, but their behavior are different.
Let's say there is already a member #a .
with getter, one obtains the current value of #a, without modifying it.
with setter, one modifies #a, and get its new value as return value.
when thinking about behavior of setter, note:
the old value of #a can not be obtained with setter, and got overwritten.
what returned by setter, is actually already known before invoking setter.
May be the attention for getters and setters is because some other languages allow you to access class variables directly. Python:
class k:
i = 100
print k.i # 100
k.i = 200
print k.i # 200
In contrast, Ruby keeps all of its variables completely private to the class and only exposes them through accessor methods.
In your example, if you remove the getter, you can indeed interact with the variable (that is: change it) trough the setter, but you can't get it back (in a regular way) when you need it.
Sometimes I see an instance variable defined as #my_variable. However, sometimes I see self.my_variable. When is each used?
Instance variables (#variable) correspond to private variables in other languages. self.myvariable is actually not a variable, but a call to a method. Similarly, if you write self.myvariable = something, it is actually a call to self.myvariable=(something). This corresponds to properties with getters and setters in other languages.
class Foo
def initialize
#bar = 42
end
def xyzzy
123
end
def xyzzy=(value)
puts "xyzzy set to #{value}!"
end
end
obj = Foo.new
puts obj.xyzzy # prints: 123
obj.xyzzy = 2 # prints: xyzzy set to 2
puts obj.bar # error: undefined method 'bar'
You can use attr_reader and attr_accessor to automatically define getters and setters for an instance variable. attr_reader will only generate a getter, while attr_accessor generates both.
class Parrot
attr_accessor :volts
def voom
puts "vooming at #{#volts} volts!"
end
end
polly = Parrot.new
polly.volts = 4000
polly.voom
Instance variables are more primary things than methods calling them. In self.myVariable, myVariable is a method referring to the instance variable #myVariable, and that method is defined usually by attr_reader or attr_accessor.
One purpose of object orientated programming is to encapsule things particular to an instance inside that instance and make it inaccessible from outside of it. This way, you can avoid unwanted conflicts of name. This is true for instance variables. They are usually parameters to be handeled within the instance, and not to be used outside of it.
Within an instance, its instance variables can be directly referred to, and hence there is no need to refer to them via method calls. You should directly call the variable #myVariable.
From outside of an instance, you cannot directly refer to the instance variables because of the reason mentioned above. But sometimes, you do need to refer to them. The purpose of using the method myVariable is to refer to the instance variable from outside of an instance.
#my_variable refers directly to the instance variable, and is (for the most part) inaccessible from outside that instance.
self.my_variable is using an accessor method (as defined with attr_reader, attr_writer or attr_accessor internally. This is in cases where there may not be an instance variable named #my_variable (as is the case with ActiveRecord model attributes) or where the internal state differs from what is exposed publicly.
In testing a getter/setter pair in a rails model, I've found a good example of behavior I've always thought was odd and inconsistent.
In this example I'm dealing with class Folder < ActiveRecord::Base.
Folder belongs_to :parent, :class_name => 'Folder'
On the getter method, if I use:
def parent_name
parent.name
end
...or...
def parent_name
self.parent.name
end
...the result is exactly the same, I get the name of the parent folder. However, in the getter method if I use...
def parent_name=(name)
parent = self.class.find_by_name(name)
end
... parent becomes nil, but if I use...
def parent_name=(name)
self.parent = self.class.find_by_name(name)
end
...then then it works.
So, my question is, why do you need to declare self.method sometimes and why can you just use a local variable?
It seems the need for / use of self in ActiveRecord is inconsistent, and I'd like to understand this better so I don't feel like I'm always guessing whether I need to declare self or not. When should you / should you not use self in ActiveRecord models?
This is because attributes/associations are actually methods(getters/setters) and not local variables. When you state "parent = value" Ruby assumes you want to assign the value to the local variable parent.
Somewhere up the stack there's a setter method "def parent=" and to call that you must use "self.parent = " to tell ruby that you actually want to call a setter and not just set a local variable.
When it comes to getters Ruby looks to see if there's a local variable first and if can't find it then it tries to find a method with the same name which is why your getter method works without "self".
In other words it's not the fault of Rails, but it's how Ruby works inherently.