What can't I access class variable from object in ruby? - ruby

I wan't to set a class variable of a class from the outside(via attr_accessor), and then access it from inside one of its objects. I'm using ruby 1.9.2. This is my code:
class Service
def initialize(id)
#my_id = id
end
class << self
attr_accessor :shared_id
end
def system_id
#my_id + ##shared_id
end
end
If I set Service.shared_id = "A2", and then call Service.new("A").system_id, this doesn't return "AA2". It displays the following error:
uninitialized class variable ##shared_id in Service
The behaviour is like if I didn't set the Service.service_id. Can someone please explain why this happens?

attr_accessor creates methods to manipulate instance variables — it does not create instance or class variables. To create a class variable, you must set it to something:
##shared_id = something
There's no helper method to generate accessor for class variables, so you have to write them yourself.
However, class variables, because of their weird lookup rules, are rarely used — avoided, even. Instead, instance variables at class-level are used.
class Service
#shared_id = thing
class << self
attr_accessor :shared_id
end
def system_id
# use self.class.shared_id; you could add a shared_id helper to generate it, too.
end
end

How about cattr_accessor?

Remember that ##class_var is global for all classes.

Related

Saving instance list in class variable

I want to store newly created Person instance inside the class variable objects, but not sure how to reference the current instance from the constructor.
class Person
##objects = {}
def initialize(key)
##objects[key] = something
end
Ideally, the result is to be able to access the dictionary of Person objects through Person.objects
Simply, in constructor function, self will refer to the current instance.
class Person
##objects = {}
def initialize(key)
##objects[key] = self
puts self # it will print the id of the current instance
end
end
Same way, if you write self in a class method, it will refer to the the class.
But from your question, you seem to be doing something like Person.objects, and it won't work, and will output the following line:
NoMethodError: undefined method `objects' for Person:Class
So, you need to write a class method for it to let the outside world access objects.
def self.objects
##objects
end
Well, there are other ways as well to access the class variables, please have a look at this question.

Ruby fields initialization

In this tiny class when the #sides=10 statement is executed?
How this statement is related to the initialize method?
class Poligon
attr_accessor :sides
#sides=10
end
I am mostly used to Java where it is common to have inline initialization for the attributes. I am now trying to understand the complete initialization procedure for Ruby but I was not able to find it.
Short answers:
The statemen #sides = 0 (which actually is an expression) is exectuted when the class expression in evaluated.
It is not related at all with the initialize method.
As you write it, the #sides variable is a class instance variable, i.e. an instance variable of the Poligon object (remember that in Ruby classes are objects of class Class). You must initialize instance variables inside a method definitions (perhaps inside the initialize method). Consider this example:
class Poligon
#class_sides = 'class instance variable'
def initialize
#instance_sides = 'instance variable'
end
end
Poligon.instance_variables
# => [:#class_sides]
Poligon.instance_variable_get(:#class_sides)
# => "class instance variable"
Poligon.new.instance_variables
# => [:#instance_sides]
Poligon.new.instance_variable_get(:#instance_sides)
# => "instance variable"
For more information about class instance variable and how they relate to class variables you can read this article by Martin Fowler.
You need to put this #sides=10 inside a method,with your current class definition.
class Poligon
attr_accessor :sides
def line
#sides=10
end
end
p = Poligon.new
p.line
puts p.sides
# >> 10
The initialize method is the constructor for the class. If you want, you can initialize your instance variables in the contructor:
class Poligon
attr_accessor :sides
def initialize(num_sides)
#sides = num_sides
end
end
But since #sides is declared as an attr_accessor, you can set/get it directly:
p = Poligon.new
p.sides = 10

Define instance method of a class after class already defined in ruby

I have some problem with extending class with instance method after separate module is included into separate class
module ActsAsCommentable
def self.included(commentable)
Thread.class_eval do
def commentable
p "disqusable is #{commentable}"
p "disqusable class is #{commentable}"
end
end
end
end
class Thread
#some code...
end
class Asset
include ActsAsCommentable
end
And now I want to call this method somelike this:
thread = Thread.new
thread.commentable
The problem is, of course is that there is no binding with include method for class eval, and I could save variables that I want to pass into class eval in ActsAsCommentable module, but I dont want to. Is there a better way?
I tried to do instead
module ActsAsCommentable
def self.included(commentable)
class << Thread
define_method :commentable do
p "disqusable is #{commentable}"
p "disqusable class is #{commentable}"
end
end
end
end
But As I guessed this creates instance method for singletone object of class and therefore I can call it only through
Thread.commentable
And again, no binding...
If I understand you correctly, you need to be able to access the commentable variable inside your Thread extension, right?
If so, just change this:
Thread.class_eval do
To this:
Thread.class_exec(commentable) do |commentable|
And it should work.

Difference between #instance_variable and attr_accessor

I Just started learning ruby and I don't see the difference between an #instace_variable and an attribute declared using attr_accessor.
What is the difference between the following two classes:
class MyClass
#variable1
end
and
class MyClass
attr_accessor :variable1
end
I searched lot of tutorials online and everybody uses different notation, Does it have to do anything with the ruby version? I also searched few old threads in StackOverflow
What is attr_accessor in Ruby?
What's the Difference Between These Two Ruby Class Initialization Definitions?
But still I am not able to figure out what is the best way to use.
An instance variable is not visible outside the object it is in; but when you create an attr_accessor, it creates an instance variable and also makes it visible (and editable) outside the object.
Example with instance variable (not attr_accessor)
class MyClass
def initialize
#greeting = "hello"
end
end
m = MyClass.new
m.greeting #results in the following error:
#NoMethodError: undefined method `greeting' for #<MyClass:0x007f9e5109c058 #greeting="hello">
Example using attr_accessor:
class MyClass
attr_accessor :greeting
def initialize
#greeting = "hello"
end
end
m2 = MyClass.new
m2.greeting = "bonjour" # <-- set the #greeting variable from outside the object
m2.greeting #=> "bonjour" <-- didn't blow up as attr_accessor makes the variable accessible from outside the object
Hope that makes it clear.
Instance variables are not directly visible outside of the class.
class MyClass
def initialize
#message = "Hello"
end
end
msg = MyClass.new
#message
#==> nil # This #message belongs to the global object, not msg
msg.message
#==> NoMethodError: undefined method `message'
msg.#message
#==> SyntaxError: syntax error, unexpected tIVAR
Now, you can always do this:
msg.instance_eval { #message }
or ask for the variable directly like this:
msg.instance_variable_get :#message
But that's awkward and sort of cheating. Poking around someone else's class may be educational, but your client code shouldn't be required to do it to get reliable results. So if you want clients to be able to see those values, don't make them use the above techniques; instead, define a method to expose the value explicitly:
class MyClass
def message
return #message
end
end
msg.message
# ==> "Hello"
Because you so often want to do that, Ruby provides a shortcut to make it easier. The code below has exactly the same result as the code above:
class MyClass
attr_reader :message
end
That's not a new type of variable; it's just a shorthand way to define the method. You can look at msg.methods and see that it now has a message method.
Now, what if you want to allow outsiders to not only see the value of an instance variable, but change it, too? For that, you have to define a different method for assignment, with a = in the name:
class MyClass
def message=(new_value)
#message = new_value
end
end
msg.message = "Good-bye"
msg.message
# ==> "Good-bye"
Note that the assignment operators are semi-magical here; even though there's a space between msg.message and =, Ruby still knows to call the message= method. Combination operators like += and so on will trigger calls to the method as well.
Again, this is a common design, so Ruby provides a shortcut for it, too:
class MyClass
attr_writer :message
end
Now, if you use attr_writer by itself, you get an attribute that can be modified, but not seen. There are some odd use cases where that's what you want, but most of the time, if you are going to let outsiders modify the variable, you want them to be able to read it, too. Rather than having to declare both an attr_reader and an attr_writer, you can declare both at once like so:
class MyClass
attr_accessor :message
end
Again, this is just a shortcut for defining methods that let you get at the instance variable from outside of the class.
attr_accesor gives you methods to read and write the instance variables. Instance variables are deasigned to be hidden from outside world so to communicate with them we should have attr_ibute accesor methods.
In OOPS we have a concept called encapsulation which means, the internal representation of an object is generally hidden from view outside of the object's definition. Only the Object 'itself' can mess around with its own internal state. The outside world cannot.
Every object is usually defined by its state and behavior, in ruby the instance variables is called internal state or state of the object and according to OOPS the state should not be accessed by any other object and doing so we adhere to Encapsulation.
ex: class Foo
def initialize(bar)
#bar = bar
end
end
Above, we have defined a class Foo and in the initialize method we have initialized a instance variable (attribute) or (property). when we create a new ruby object using the new method, which in turn calls the initialize method internally, when the method is run, #bar instance variable is declared and initialized and it will be saved as state of the object.
Every instance variable has its own internal state and unique to the object itself, every method we define in the class will alter the internal state of the object according to the method definition and purpose. here initialize method does the same, such as creating a new instance variable.
var object = Foo.new(1)
#<Foo:0x00000001910cc0 #bar=1>
In the background, ruby has created an instance variable (#bar =1) and stored the value as state of the object inside the object 'object'. we can be able to check it with 'instance_variables' method and that methods returns an array containing all the instance variables of the object according to present state of the object.
object.instance_variables
#[
[0]: #bar
]
we can see '#bar' instance variable above. which is created when we called the initialize method on the object. this '#bar' variable should not be visible (hidden) by default and so it cannot be seen by others from outside of the object except the object, from inside. But, an object can mess around with its own internal state and this means it can show or change the values if we give it a way to do so, these two can be done by creating a new instance methods in the class.
when we want to see the #bar variable by calling it we get an error, as by default we cannot see the state of an object.
show = object.bar
#NoMethodError: undefined method `bar' for #<Foo:0x00000001910cc0 #bar=1>
#from (irb):24
#from /home/.rvm/rubies/ruby-2.0.0-p648/bin/irb:12:in `<main>'
But we can access the variables by two methods, these two are called setter and getter methods, which allow the object to show or change its internal state (instance variables/attributes/properties) respectively.
class Foo
def bar
#bar
end
def bar=(new_bar)
#bar = new_bar
end
end
We have defined a getter(bar) and setter(bar=) methods, we can name them any way but the instance variable inside must the same as instance variable to which we want to show or change the value. setters and getters are a violation to OOPS concepts in a way but they are also very powerful methods.
when we define the two methods by re-opening the class and defining them, when we call the object with the methods, we can be able to view the instance variables(here #foo) and change its value as well.
object.bar
1
object.bar=2
2
object.bar
2
Here we have called the bar method (getter) which returns the value of #bar and then we have called bar= method (setter) which we supplied a new_value as argument and it changes the value of instance variable (#bar) and we can look it again by calling bar method.
In ruby we have a method called attr_accessor , which combines the both setter and getter methods, we define it above the method definitions inside the class. attr_* methods are shortcut to create methods (setter and getter)
class Foo
attr_accessor :bar
end
we have to supply a symbol (:bar) as argument to the attr_accessor method which creates both setter and getter methods internally with the method names as supplied symbol name.
If we need only a getter method, we can call attr_reader :bar
If we need only a setter method, we can call attr_writer :bar
attr_accessor creates both attr_writer and attr_reader methods
we can supply as many instance variables as we want to the attr_* methods seperated by commas
class Foo
attr_writer :bar
attr_reader :bar
attr_accessor :bar, :baz
end
Because attr_accessor defines methods, you can call them from outside the class. A #variable is only accessible from inside the class.
And another answer more compact (for Java developers)
attr_accessor :x creates the getters and setters to #x
class MyClassA
attr_accessor :x
end
is the same as
class MyClassB
def x=(value) #java's typical setX(..)
#x=value
end
def x
#x
end
end

Create property as method on class in Ruby

Rails has these cool properties that seem to be actually methods. For example:
class SomeController < ApplicationController
before_filter :authenticate!
end
What are these actually called and how would you create your own? For example, in one of my models I want to be able to have a dynamic property that selects an internal method for processing some results:
class MyModel < ActiveRecord::Base
active_method :some_class_method
end
How would I set this up so I can set active_method like that and be able to access the active_method symbol as an instance var?
Edit for elaboration:
So give this starter below, I need to figure out how to define "selected_method" so that it defines a accessor or instance variable so "called_selected_method" calls "method_b".
class MyClass
selected_method :method_b
def call_selected_method
end
private
def method_a
puts 'method_a'
end
def method_b
puts 'method_b'
end
end
c = MyClass.new
c.call_selected_method # should put 'method_b'
It's actually just a method call to a method defined on the class. before_filter is provided by a ruby Module, which is mixed in to ActionController.
Creating your own methods similar to before_filter is as easy as:
Define a class method on your Class
Call that method in any concrete implementations of your class.
Some example code:
class MyClass
class << self
def some_function(*args)
# your code here
end
end
some_function "foo"
end
If you wanted to abstract it further, you can put the class method in to a Module, and then include that module in to your class(es).
UPDATE:
In relation to your asking of how to get a call of some_function to set an instance variable on your class, you can't, as class methods cannot affect specific instances of that class.
I have to wonder, though... you're writing a method that will just act as a proxy to your other method, and would be hard-coded in to the class definition. That offers no benefit to you, and would just make your code redundantly complicated.

Resources