class Test
def self.states
##states ||= OpenStruct.new({initial: 'initial', started: 'started'}).freeze
end
end
Does above code mean ##states is frozen ?
Is ##states re-assignable then how?
Is writing #states and ##states same in class methods ?
If ##states is not-frozen or re-assignable then how can I lock ##states once it is set so that it is not re-assignable?
Does above code mean ##states is frozen?
Yes (sort-of). You called .freeze on the object, so the object is frozen. I.e. technically the "frozen" thing is the object referenced by the variable, not the variable itself:
[1] pry(main)> x = "hello".freeze
=> "hello"
[2] pry(main)> x.frozen?
=> true
[3] pry(main)> x = "world"
=> "world"
[4] pry(main)> x.frozen?
=> false
Is ##states re-assignable then how?
There's no "public interface" to change the variable, but you can do it via meta-programming:
Test.class_variable_set('##states', 'CHANGED!')
Is writing #states and ##states same in class methods?
No. There's a subtle difference between an instance variable in a class and a class variable. For example, see this answer for a more detailed explanation.
If ##states is not-frozen or re-assignable then how can I lock ##states once it is set so that it is not re-assignable?
You can't make it impossible to change/reassign anything in ruby; the best you can do is make it very awkward -- i.e. you have to write something "hacky" to change it.
In other words, you can remove any "public interface" and make the object frozen (which is exactly what you've done already), but - by the nature of ruby being a dynamic language with powerful meta-programming - there's always going to be some back-door way of changing a variable if you're really determined. For instance, see this library.
This isn't unique to ruby -- for example, it's possible to change constants in C/C++ by using pointers.
Related
In a common application we use instance variables so that we can access them in our views. But in a Rails api application what would the need be?
Is there any performance difference between using a local or instance variable In this context of Controllers?
I do not understand why rails uses instance variables in the create and index method in an api application generated by scaffold if the variable is not reused
def show
user = User.find(params[:id])
render json: UserSerializer.new(user)
end
def show
#user = User.find(params[:id])
render json: UserSerializer.new(#user)
end
In this exact example, there is no functional difference.
Is there any performance difference? Or is there material performance difference? I do not know the answer to the first question. The answer to the second question, I imagine, is 'no' unless you are doing this at some unimaginably large scale. Even then, it's hard to imagine.
BTW, you could just do:
def show
render json: UserSerializer.new(User.find(params[:id]))
end
In your example, there is no need for a variable, either user or #user.
There is a very clear practical difference in how lexical and instance variables work:
class Thing
def initialize
#ivar = "Hello World"
end
def foo
#ivar
end
end
> Thing.new.foo
=> "Hello World"
Since instance variables are attached to the instance they can be shared among methods of an object without passing by value as typically used by callbacks:
class API::V1::ThingsController < ::ApiController
before_action :set_thing, except: [:create, :index]
def show
respond_with #thing
end
# ...
private
def set_thing
#thing = Thing.find(params[:id])
end
end
This can be immensely useful when considering the convention over configuration focus of rails. Controller IVARs are also available in the view through the view context.
Lexical variables on the other hand only exist in the lexical scope where the are defined (the method, block, proc or lambda):
class Thing
def initialize
lex = "Hello World"
end
def foo
lex
end
end
> Thing.new.foo
NameError: undefined local variable or method `lex' for #<Thing:0x007f87068b5968>
They are preferable when you need a short lived variable with a local scope. Rails also has locals which is actually a hash where you can stuff things when rendering which should not be conflated with the Ruby concept of lexical variables. Rails uses method_missing in the view context to proxy to the locals hash.
The performance difference is most likely extremely negible as both are just variables that are bound to a scope - either the object or a method/block. The lexical variable will recycled by the GC when the scope is closed (the method finishes) though while an instance variable will persist with the object. This is rarely an issue though.
The performance difference will be negligible.
But there's two competing guidelines at work. One is "Always use the weakest construction." Don't use double "quotes" if you can use single 'quotes'. Don't use a regular expression if you can use String#index. Don't use an instance variable if you can use a local variable.
The other guideline is "Design for testing." If you use an instance variable, your test can inspect it with assigns(:user). That rule trumps the "weakest construction" rule. So use an instance variable, and write lots of automated tests!
there is no difference talking about functionality in that example. but creating an instance variable is to let that variable be accesible later, maybe on the view or in another method, in this case, talking about api's (you don't have views), if you do not plan to use #user in another method inside that controller for example, you don't need to create it, with just a local variable, it's enough.
talking about performance, I don't think there will be much differences, at least something noticeable.
And as a comment:
"An instance variable continues to exist for the life of the object that holds it. A local variable exists only within a single method, block or module body."
I have been trying to learn Ruby from 'The Well-grounded Rubyist' and I came across the idea of adding methods to an object at run-time:
obj = Object.new
obj.respond_to? "hello" # Returns false
def obj.hello
puts "something"
end
obj.respond_to? "hello" # Returns true
obj.hello() # Output is "something"
I have a background in Python and Java, and I cannot imagine any way for me to use this new idea. So, how is this useful? How does it fit into the spirit of object-oriented programming? Is it expensive to do this at run-time?
There's always a long list of things you can do in any language but shouldn't do without a good reason and extending a single object is certainly high on that list.
Normally you wouldn't define individual methods, but you might include a bunch of them:
module Extensions
def is_special?
true
end
end
obj = Object.new
obj.send(:extend, Extensions)
obj.is_special?
# => true
ActiveRecord from Rails does this to dynamically create methods for models based on whatever the schema is at the time the Rails instance is launched, so each column gets an associated method. This sort of dynamic programming can be used to make the code adapt seamlessly to a changing environment.
There's a lot of cases where you'll want to spell this out explicitly so your methods are well documented, but for cases where it doesn't matter and responding dynamically is better than maintaining two things, like schema and the associated methods in your code, then it could be the best option.
I was implementing a form that includes a hard-coded dropdown for a collection and I was wondering what would be the best solution, I know both ways exposed below work, still I did as follows:
class Example
# Options for Example.
self.options
[ 'Yes', 'No', 'Not sure' ]
end
end
which is called by Example.options, but I know it is possible to do as follows as well:
class Example
# Options for Example.
OPTIONS = [ 'Yes', 'No', 'Not sure' ]
end
that would be called with Example::OPTIONS.
The question is, is any of these the good way or it just doesn't matter at all?
The latter is better. If it were a method, a new array and new strings will be created every time it is called, which is a waste of resource.
TL;DR: It depends. Are the values meant to be used outside the class? Could they ever become dynamic? Could they change for subclasses?
As #sawa wrote, the downside of the method (written this way) is that a new array and strings are created each time.
A better way to write it would be:
class Example
def self.options
#options ||= ['Yes', 'No', 'Not sure']
end
end
The array is stored in the instance variable #options, to avoid creating a new array each time.
Written this way, the method is very similar to the constant.
One key difference is if Example is subclassed, it will be more natural to refine the options method than the constant OPTIONS:
class Parent < Example
def self.options
#options ||= [*super, 'Extra']
end
end
To do something similar with constants is difficult. Imagine that your list of options is used in a class method, this would look like:
class Example
OPTIONS = ['Yes', 'No', 'Not sure']
def self.foo(arg)
puts "Available options:",
self::OPTIONS # The self:: is needed here
# ...
end
end
class Parent < Example
OPTIONS = [*superclass::OPTIONS, 'Extra']
end
The tricky thing about constants, is that self::OPTIONS and OPTIONS are not the always same, while self.options and options are the same. Constants are usually used without specifying the scope (e.g. OPTIONS instead of self::OPTIONS) and inheritance will simply not work in that case.
Note that the method gives you the opportunity to make the result dynamic (i.e. return different results depending on other circumstances) without changing the API.
Final note: I'd recommend calling freeze on your array, to avoid anyone modifying it.
What I usually do is have a mix of above-mentioned techniques:
class Player
JURISDICTIONS = %i(de uk ru)
def self.jurisdictions
JURISDICTIONS
end
end
It has few advantages:
It provides a clean interface, encapsulating a constant (you call Player.jurisdictions instead of Player::JURISDICTIONS).
Additional logic can be added later just by altering method.
The method can be stubbed in tests.
IMHO, performance does not matter here.
Update:
Constant can bee hidden using private_constant method (http://ruby-doc.org/core-2.3.0/Module.html#method-i-private_constant)
To further refine Artur's suggestion I would go with a class variable in order to hide visibility of the constant.
class Player
##jurisdictions = %i(de uk ru)
def self.jurisdictions
##jurisdictions
end
end
hi i m new to ruby on rails please let me know is it possible to declare a variable within the function/method
def fun1
#initialized a global variable
end
def fun2
#access value
end
is it possible get value of a variable declared in fun1 function by fun2 function
To create a truly global variable, use $:
def fun1
$foo = 'bar'
end
def fun2
puts $foo
end
Here $foo is available outside the class instance once fun1 has been called.
As noted in the first comment, this should be used sparingly:
They are dangerous because
they can be written to from anywhere. Overuse of globals can make
isolating bugs difficult; it also tends to indicate that the design of
a program has not been carefully thought out.
What you're probably asking for is an instance variable, which uses #:
def fun1
#foo = 'bar'
end
def fun2
puts #foo
end
Here #foo is available anywhere in the current instance of the class, again once it has been declared by calling fun1.
See for example this on the various variable scopes in ruby.
First of all, it would be better if you could share your actual scenario for what you need to define a global variable from a function. There might be a better, manageable, DRY approach for your solution.
Secondly, apart from the answer from "Thilo", here are few references showing the usage of global variables for rails in different situations. Not just for ruby. You need it for rails right?
https://stackoverflow.com/a/4110947/1160106
https://stackoverflow.com/a/3600860/1160106
I'm working with Ruby and Rails, so any Rails extension of Ruby should be fine too.
I'm wondering if there's a way to effectively force a type on instance variables (rather, their setters and getters) that's easier than manually defining them.
The class method attr_accessor and the like don't enforce a type. I noticed for instance that Rails' ActiveRecord::Base class does automatic casting on setters. It knows from the database that a particular active record variable is an integer, and setting it with #record.integer_variable = '1' automatically casts the argument and allows further access through #record.integer_variable # => 1.
Is there a way to tap into this?
I could write my own getters and setters as class methods, but if smarter folk have already done the heavy lifting, I'd rather not have to trust myself.
I don't know if there's already something about it, but you can solve this problem with just a few lines of meta-programming:
module EnforceTypes
def attr_accessor_of_type(name, type)
send :define_method, name do
instance_variable_get("##{name}")
end
send :define_method, "#{name}=" do |v|
raise ArgumentException unless v.is_a? type
instance_variable_set("##{name}", v)
end
end
end
Usage:
class MyClass
extend EnforceTypes
attr_accessor_of_type :some_string, String
end
Of course you can make it a little smart by changing the 2nd emitted method, performing some conversions, etc.
Here's a nice reference: http://www.raulparolari.com/Ruby2/attr_accessor
And remember, almost anything that you can do by manually copy-and-pasting lots of code, can be solved with meta-programming.