Access variable with name from string - ruby-on-rails

#result.instance_variable_get("#{#most}_max_count".to_sym)
#most is a single-digit string, for instance i. This code bit gives the error
`i_max_count' is not allowed as an instance variable name
(What I am trying to access is #result.i_max_count)
edit:
What I want to do is to set the value of #result.i_max_count to something.
Class for #result is pretty much empty:
class Result < ActiveRecord::Base
attr_accessor :least, :most
end

The parameter of instance_variable_get should be valid instance variable name: #i_max_count for example.
So you can slightly change your code:
#result.instance_variable_get("##{#most}_max_count".to_sym)
But question has tag "ruby-on-rails" so probably you are working with Hash. This way you can try that (thx for #FrederickCheung):
#result["#{#most}_max_count"]
or even this way:
#result.instance_variable_get("#attributes")["#{#most}_max_count"]
Or using eval:
eval("#rezult.#{#most}_max_count")

The instance variable names always have to start with an # sigil . The below snippet shows usage
Eg
class Ankit
def initialize(name)
#name = name
end
end
UPDATED:
1.9.3p392 :033 > a = Ankit.new("ankit")
=> #<Ankit:0x007fb3c39c79e8 #name="ankit">
1.9.3p392 :034 > a.instance_variable_get("#name")
=> "ankit"
In your case check 2 things
Is #i_max_count set?
If yes than use it obj.instance_variable_get("#i_max_count")

Related

Create or rename method in Rails

How to add method, or rename method name?
I have code like this:
"X Y".split().first => X
"X Y".split().last => Y
In a string, there is always only one space.
I'd like to change this to:
"X Y".a => X
"X Y".b => Y
How to achieve this goal?
Ryby 2.7, Rails 6
Regards
Not sure why you would want to do this in the first place since you can get character at any place in a string with:
"abc".chr == "a"
"abc"[0] == "a"
"abc"[-1] == "c"
If you really want to add methods to a string create a module:
module MyStringExtensions
def a
chr
end
def b
self[-1]
end
end
You can then extend string instances with the module to augment them:
"abc".extend(MyStringExtensions).a # "a"
You can also monkeypatch the String class if you really want to:
String.include(StringExtensions)
Using a module is generally better then reopening someone elses class as it gives a better stack trace for debugging.
You could create extensions methods for String class like described here.
class String
def a
self.split().first
end
...
end

What is the practical purpose of instance variables?

I'm new to ruby rails, and I'm struggling to understand what the purpose of instance variables are.
What is the point of making a variable into an instance variable?
Basically why would I do this:
class User
def initialize(var1)
#name = var1
end
end
over this:
class User
def initialize(var1)
name = var1
end
end
And in what types of situations would I want to use an instance variable over just a regular variable?
The practical use for this is that if you need a variable to persist across function calls, make it an instance variable.
after you define the instance variable, you can call the value of this on another function and you will have the value.
In general an instance variable is local and persisted inside an instance of an object, whereas a local variable is only local and persisted inside a function/object/block scope.
in your example if you have another method on your user class, you can use the value of #name on that other method, but coulnd't use var1 outside of initialize method.
class User
def initialize(var1)
#name = var1
end
def greetings
"hello #{#name}"
end
end
class People
def age
#age
end
def age= age
#age = age
end
end
def show people
age = people.age || '22'
p "Hello, my age is #{age}"
end
people = People.new
show people
=> 'Hello, my age is 22'
age
=> NameError: undefined local variable or method 'age' for main:Object
user.age = 21
greet people
=> 'Hello, my age is 21'
#age
=> nil
Notice that both variable types are local to a specific context though. #age is defined within the people instance, so when you call people.age you are calling the age function in the age instance, in which #age is defined. age is only defined in the show function, so when you call p "Hello, my age is #{age}" you are able to get a value for age because you are within the scope in which it is defined.
Because your instance variable will be accessible to your view code, including within forms and passing data to paths. That's probably the most common, practical use case for them. In your example, I could do the following:
<p>User: <%= "#{#name}" %></p>
And, instead of seeing "#name" in my corresponding paragraph in the rendered H.T.M.L, you'd see the value of that instance variable - whereas the inverse:
<p>User: <%= "#{name}" %></p>
...will probably result in an ActionView error, since "name" is undefined, according to it.

Replace word using gsub function in ruby

i am trying to replace some word from a string with gsub function in ruby, but sometimes that works fine and in some cases giving this error? is there any issues with this format
NoMethodError (undefined method `gsub!' for nil:NilClass):
model.rb
class Test < ActiveRecord::Base
NEW = 1
WAY = 2
DELTA = 3
BODY = {
NEW => "replace this ID1",
WAY => "replace this ID2 and ID3",
DELTA => "replace this ID4"
}
end
another_model.rb
class Check < ActiveRecord::Base
Test::BODY[2].gsub!("ID2", self.id).gsub!("ID3", self.name)
end
Ah, I found it! gsub! is a very weird method. Firstly, it replaces the string in place, so it actually modifies your string. Secondly, it returns nil when no substitution has been made. This all sums up to the error you're getting.
The first time you execute that call, it modifies the string assigned to a constant, so it reads as "replace this 3 and name". When you try to run it for a second time, the first gsub will fail to find a string it is looking for so will return nil. The second gsub is then executed on the nil.
On how to solve it - it all depends on what you're trying to achieve. For me, it is somewhat risky to change other class constants (breaks encapsulation). If you just want to get the result without modifying the original string, use gsub (no bang). Or even better, convert those string into a method and use interpolation instead of substitution.
If the strings are just patterns, that should be replaced before get used. A better way would be string Interpolation.
class Test < ActiveRecord::Base
# Here use symbols instead, because symbols themselfs are immutable
# so :way will always equal :way
BODY = {
:new => "replace this %{ID1}",
:way => "replace this %{ID2} and %{ID3}",
:delta => "replace this %{ID4}"
}
end
# HERE you should create another constant based on the
# Test class constants
class Check < ActiveRecord::Base
BODY = {
:way => Test::BODY[:way] % {ID2: self.id, ID3: self.name}
}
# Or you can make it a method
def self.body
Test::BODY[:way] % {ID2: self.id, ID3: self.name}
end
end
this will change every apearance of the hash keys in the string
for example:
str = "%{num1} / %{num1} = 1"
str % {num1: 3} # 3 / 3 = 1
And like #BroiSatse said, you should not change constants of other classes or within the same class itself, at the end they are constants.

Struct with types and conversion

I am trying to accomplish the following in Ruby:
person_struct = StructWithType.new "Person",
:name => String,
:age => Fixnum,
:money_into_bank_account => Float
And I would like it to accept both:
person_struct.new "Some Name",10,100000.0
and
person_struct.new "Some Name","10","100000.0"
That is, I'd like it to do data conversion stuff automatically.
I know Ruby is dinamically and I should not care about data types but this kind of conversion would be handy.
What I am asking is something similar to ActiveRecord already does: convert String to thedatatype defined in the table column.
After searching into ActiveModel I could not figure out how to to some TableLess that do this conversion.
After all I think my problem may require much less that would be offered by ActiveModel modules.
Of course I could implement a class by myself that presents this conversion feature, but I would rather know this has not yet been done in order to not reinvent the wheel.
Tks in advance.
I think that the implementation inside a class is so easy, and there is no overhead at all, so I don't see the reason to use StructWithType at all. Ruby is not only dynamic, but very efficient in storing its instances. As long as you don't use an attribute, there is none.
The implementation in a class should be:
def initialize(name, age, money_into_bank_account)
self.name = name
self.age = age.to_i
self.money_into_bank_account = money_into_bank_account.to_f
end
The implementation in StructWithType would then be one layer higher:
Implement for each type a converter.
Bind an instance of that converter in the class.
Use in the new implementation of StructWithType instances (not class) the converters of the class to do the conversion.
A very first sketch of it could go like that:
class StructWithType
def create(args*)
<Some code to create new_inst>
args.each_with_index do |arg,index|
new_value = self.converter[index].convert(arg)
new_inst[argname[index]]= new_value
end
end
end
The ideas here are:
You have an instance method named create that creates from the factory a new struct instance.
The factory iterates through all args (with the index) and searches for each arg the converter to use.
It converts the arg with the converter.
It stores in the new instance at the argname (method argname[] has to be written) the new value.
So you have to implement the creation of the struct, the lookup for converter, the lookup for the argument name and the setter for the attributes of the new instance. Sorry, no more time today ...
I have used create because new has a different meaning in Ruby, I did not want to mess this up.
I have found a project in github that fulfill some of my requirements: ActiveHash.
Even though I still have to create a class for each type but the type conversion is free.
I am giving it a try.
Usage example:
class Country < ActiveHash::Base
self.data = [
{:id => 1, :name => "US"},
{:id => 2, :name => "Canada"}
]
end
country = Country.new(:name => "Mexico")
country.name # => "Mexico"
country.name? # => true

Ruby returns TypeError: can't convert Object into String

I'm starting to work with Ruby and I have the following module:
module RadioreportHelper
#totalsum = 0
#radio
#daysAndTotals
def load(service, transactionsPerDay)
puts "#{service} : #{transactionsPerDay}"
#radio = service
#daysAndTotals = transactionsPerDay
transactionsPerDay.each{|day, total|
#totalsum += total
}
end
attr_reader :radio, :daysAndTotals, :totalsum
end
I'm running the following unit test case:
class RadioreportHelperTest < ActionView::TestCase
fixtures :services
def test_should_return_populated_radio_module
service = Service.find_by_name("Mix")
transactionsPerDay = {1=>20, 2=>30, 4=>40, 5=>50}
radioReport = RadioreportHelper.load(service, transactionsPerDay)
assert_not_nil(radioReport)
assert_equal("Mix", radioReport.radio.name)
end
end
But I always get the following error:
TypeError: can't convert Service into String
I want the service object to be in the module RadioreportHelper and stored it in the #radio variable not the string.
Thanks, for the all the help guys!
Try adding a to_s method to your Service model.
def to_s
service # or some other method in the model that returns a string
end
It is not necessary to call to_s from inside an interpolated expression, i.e. "#{service}" will return the result of service.to_s.
EDIT
Never mind all of this. Your RadioreportHelper.load method is not being reached -- instead you are getting load from ActiveSupport::Dependencies::Loadable. Try renaming the load method to something else.
(I hate name collisions.)
You should definitely try this:
puts "#{service.to_s} : #{transactionsPerDay}"
Although I am not sure how interpolation for hashes is handled in strings either, so you may need to use
puts "#{service.to_s} : #{transactionsPerDay.to_s}"

Resources