Equivalent ruby code to following without attr_accessor? - ruby

This is a Java Code :
public class test{
public static void main(String args[]){
number A = new number();
System.out.println(A.b);
}
}
class number{
int b = 100;
}
Is there a equivalent of above code in ruby without attr_accessor ?
Why can't we access member variables using '.' like in java ? or is there a way i am unaware of in ruby ... ?

Instance variables are hidden by default. You can get around this by using instance_variable_get and instance_variable_set, but these are private (you can get around this too if you must) because it's unidiomatic to do such things.
In Ruby, when you say foo.bar, you are invoking the bar method on your foo object (with no arguments). When you say foo.bar = 5, you are invoking the bar= method with argument 5.
All attr_accessor does is provide implementations of bar and bar= for you, but this:
class MyClass
attr_accessor :bar
end
is equivalent to
class MyClass
def bar
#bar
end
def bar=(new_bar)
#bar = new_bar
end
end
This lets you later replace the implementation with something else if you wish. Instance variables are supposed to be private to that object, so I wouldn't recommend trying to work around this unless you're doing heavy-duty metaprogramming.

If you just want to pass around structured data, then you can use the Ruby Struct class, which will work more like you'd expect from your example:
Number = Struct.new(:value)
n = Number.new
n.value = 123
n.value # => 123

The equivalent is using Ruby's attr_accessor. Why do you want to avoid it?
class number
attr_accessor :b
end
Then you can call
a = number.new
a.b = 1

Related

Ruby class, arguments being passed around methods, instance variable?

I'm having this problem which I think it might be a code smell, I have a class that receives an argument in its initialiser and contains one public and several private methods - everything normal. Example:
class Foo
def initialize(a)
#a = a
end
def apply?(examples)
foo_1(examples)
end
private
def foo_1(examples)
foo_2(examples) ? 1 : 2
end
def foo_2(examples)
examples.size > #a
end
end
My problem here, is 'examples' that is received by the public method being carried around over and over the private methods, it doesn't look pretty and it seems like a code smell, what's the best approach here? Make it an instance variable inside the public method?
Thanks
Yes, this may be considered a code smell if the number of private methods accepting examples is bigger than 1-2.
One thing to consider would be to extract a class to represent the rule here.
For example:
class Foo
def initialize(a)
#a = a
end
def apply?(examples)
size_rule_applies?(examples) ? 1 : 2
end
private
def size_rule_applies?(examples)
SizeRule.new(#a, examples).apply?
end
class SizeRule
def initialize(a, examples)
#a = a
#examples = examples
end
def apply?
#examples.size > #a
end
end
end
I wouldn't make the examples an instance variable of the Foo class as there's a risk it would persist in memory between the calls to that object. I've seen bugs like that.
If examples changes dynamically then making it instance variable is not an option. You'll either need to instantiate Foo for every examples or you'll end up having mutable Foo where examples itself is changing, which is also not good.
Your code looks fine. The only thing that concerns me is that one method depends on another. It's usually not a big deal, but this would look better to me:
def apply?(examples)
foo_1(examples) && foo_2(examples)
end
Another option is to use block:
class Foo
def initialize(a)
#a = a
end
def apply?(examples)
foo_1 { examples }
end
private
def foo_1
v = foo_2 { yield.size }
v ? 1 : 2
end
def foo_2
yield > #a
end
end
Since the class Foo does nothing else presently than just evaluate .apply?(examples) I will advice examples be added to the initializer and made an instance variable. This is simpler, more efficient and more obvious.
class Foo
def initialize(a, examples)
#a = a
#examples = examples
end
def apply?
foo_1
end
private
def foo_1
foo_2 ? 1 : 2
end
def foo_2
#examples.size > #a
end
end

Dynamic Variables to access class methods in Ruby

Working in Ruby, we have to use a 3rd party Framework, which has a class setup something like this:
class Foo
attr_accessor :bar
def initialize()
end
end
class Poorly_Designed_Class
attr_accessor :thing1
attr_accessor :thing2
attr_accessor :thing3
attr_accessor :thing4
attr_accessor :thing5
# through :thing_n .. number defined at runtime
def initialize()
#thing1 = Foo.new
#thing2 = Foo.new
#thing3 = Foo.new
#thing4 = Foo.new
#thing5 = Foo.new
end
end
I don't know how many "things" there are until run time. there could be 5 or their could be 50.
What I would like to do is something like:
pdc = Poorly_Designed_Class.new
for i in 0..numberOfThings do
pdc."thing#{i}".bar = value[i]
end
The above doesn't work.
I've also tried accessing it via:
instance_variable_set("pdc.thing#{i}.bar",value)
I understand that the class should be using an array or hash. Unfortunately I can't do anything about how the class is designed and we have to use it.
Is what i'm trying to do even possible?
You could either try to call the getter (preferably, since it honors encapsulation):
pdc = PoorlyDesignedClass.new
1.upto(number_of_things.times do |i|
pdc.public_send(:"thing#{i}").bar = value[i]
end
or get the instance variable (less preferred, since it breaks encapsulation):
pdc = PoorlyDesignedClass.new
1.upto(number_of_things) do |i|
pdc.instance_variable_get(:"#thing#{i}").bar = value[i]
end
So, you were on the right track, there were just two problems with your code: instance variable names start with an # sign, and . is not a legal character in an identifier.
You're using Object#instance_variable_set incorrectly. The first argument must be a string or a symbol representing the name of an instance variable including the # prefix: e.g. "#thing{i}". However you actually want to get the value of an instance variable and then send #bar= to it. That can be done with Object#instance_variable_get:
1.upto(numberOfThings) { |i| pdc.instance_variable_get("#thing#{i}").bar = value[i] }
That's a bit long and since attr_acessor :thingX defines getter methods, it's usually preferable to call them with Object#public_send instead of directly accessing the instance variable (a getter method might do something else than just returning a value):
1.upto(numberOfThings) { |i| pdc.public_send("thing#{i}").bar = value[i] }

Reflection in ruby?

I am curious how this works. For example if I create a factory pattern based class where you can "register" classes for later use and then do something like
FactoryClass.register('YourClassName', [param, param, ...]);
FactoryClass.create('your_class_name').call_method_from_this_object
where 'class_name' is a key in a hash that maps to value: ClassName
is there anything like php reflection, where I can create an instance of a class based on a string name and pass in the arguments in? (in php the arguments would be an array of them that php then knows how what to do with)
So if we take a real world example:
class Foo
attr_reader :something
def initialize(input)
#something = input
end
def get_something
return #something
end
end
# In the factory class, foo is then placed in a hash: {'foo' => 'Foo'}
# This step might not be required??
FactoryClass.create('Foo', ['hello'])
# Some where in your code:
FactoryClass.create('foo').get_something # => hello
Is this possible to do in ruby? I know everything is essentially an object, but I haven't seen any API or docs on creating class instances from string names like this and also passing in objects.
As for the hash above, thinking about it now I would probably have to do something like:
{'foo' => {'class' => 'Foo', 'params' => [param, param, ...]}}
This way when you call .create on the FactoryClass it would know, ok I can instantiate Foo with the associated params.
If I am way off base, please feel free to educate me.
Check out Module#const_get (retrieving a constant from a String) and Object#send (calling a method from a String).
Here is an answer that doesn't use eval.
PHP's Reflection is called Metaprogramming in Ruby, but they are quite different. Everything in Ruby is open and could be accessed.
Consider the following code:
class Foo
attr_reader :something
def initialize(input)
#something = input
end
def get_something
return #something
end
end
#registered = { }
def register(reference_name, class_name, params=[])
#registered[reference_name] = { class_name: class_name, params: [params].flatten }
end
def create(reference_name)
h = #registered[reference_name]
Object.const_get(h[:class_name]).new(*(h[:params]))
end
register('foo', 'Foo', ['something'])
puts create('foo').get_something
You can use Object#const_get to get objects from strings. Object.const_get('Foo') will give you the object Foo.
However, you don't need to send class name as string. You can also pass around the class name as object and use that directly.
class Foo
attr_reader :something
def initialize(input)
#something = input
end
def get_something
return #something
end
end
#registered = { }
def register(reference_name, class_name, params=[])
#registered[reference_name] = { class_name: class_name, params: [params].flatten }
end
def create(reference_name)
h = #registered[reference_name]
h[:class_name].new(*(h[:params]))
end
register('foo', Foo, ['something else'])
puts create('foo').get_something
Actually one of the strong points in ruby is meta-programming. So this is really easy to do in ruby.
I am going to skip the registering part, and jump straight to the creation
A simple implementation would be this
class FactoryClass
def self.create(class_name, params)
klass = Object.const_get(class_name)
klass.new(*params)
end
end
and then you can just do:
FactoryClass.create('YourClassName', [param, param, ...]);
and this would be equivalent to calling
YourClassName.new(param, param, ...)

A more concise way of assigning instance variables from initialize?

I have a few classes I'm using to contain data (and a few methods on it) in Ruby. For instance:
class Foo
def initialize(bar, biz, baz)
#bar=bar
#biz=biz
#baz=baz
end
end
Is there a less repetitive way of propagating these initialization arguments into instance variables?
One liner, but I find this can obscure things:
#bar,#biz,#baz = bar,biz,baz
class Foo
def initialize(*args)
raise ArgumentError unless args.length == 3
#bar, #biz, #baz = args
end
end
One quick way is to use a Struct:
class Foo < Struct.new(:bar, :biz, :baz)
# custom methods go here
end
Struct.new will return a class with the initializer and accessors set up for you (other than that, it's just a normal class). If you don't need any custom methods, you can also define a struct inline (e.g. Foo = Struct.new(:bar, :biz, :baz)).

How do I call a method that is a hash value?

Previously, I asked about a clever way to execute a method on a given condition "Ruby a clever way to execute a function on a condition."
The solutions and response time was great, though, upon implementation, having a hash of lambdas gets ugly quite quickly. So I started experimenting.
The following code works:
def a()
puts "hello world"
end
some_hash = { 0 => a() }
some_hash[0]
But if I wrap this in a class it stops working:
class A
#a = { 0 => a()}
def a()
puts "hello world"
end
def b()
#a[0]
end
end
d = A.new()
d.b()
I can't see why it should stop working, can anyone suggest how to make it work?
that code doesn't work. it executes a at the time it is added to the hash, not when it is retrieved from the hash (try it in irb).
It doesn't work in the class because there is no a method defined on the class (you eventually define a method a on the instance.
Try actually using lambdas like
{0 => lambda { puts "hello world" }}
instead
First of all, you are not putting a lambda in the hash. You're putting the result of calling a() in the current context.
Given this information, consider what the code in your class means. The context of a class definition is the class. So you define an instance method called a, and assign a class instance variable to the a hash containing the result of calling a in the current context. The current context is the class A, and class A does not have a class method called a, so you're trying to put the result of a nonexistent method there. Then in the instance method b, you try to access an instance variable called #a -- but there isn't one. The #a defined in the class context belongs to the class itself, not any particular instance.
So first of all, if you want a lambda, you need to make a lambda. Second, you need to be clear about the difference between a class and an instance of that class.
If you want to make a list of method names to be called on certain conditions, you can do it like this:
class A
def self.conditions() { 0 => :a } end
def a
puts "Hello!"
end
def b(arg)
send self.class.conditions[arg]
end
end
This defines the conditions hash as a method of the class (making it easy to access), and the hash merely contains the name of the method to call rather than a lambda or anything like that. So when you call b(0), it sends itself the message contained in A.conditions[0], which is a.
If you really just want to pretty this sort of thing up,
why not wrap all your methods in a class like so:
# a container to store all your methods you want to use a hash to access
class MethodHash
alias [] send
def one
puts "I'm one"
end
def two
puts "I'm two"
end
end
x = MethodHash.new
x[:one] # prints "I'm one"
x.two # prints "I'm one"
or, to use your example:
# a general purpose object that transforms a hash into calls on methods of some given object
class DelegateHash
def initialize(target, method_hash)
#target = target
#method_hash = method_hash.dup
end
def [](k)
#target.send(#method_hash[k])
end
end
class A
def initialize
#a = DelegateHash.new(self, { 0 => :a })
end
def a()
puts "hello world"
end
def b()
#a[0]
end
end
x = A.new
x.a #=> prints "hello world"
x.b #=> prints "hello world"
One other basic error that you made is that you initialized #a outside of any instance method -
just bare inside of the definition of A. This is a big time no-no, because it just doesn't work.
Remember, in ruby, everything is an object, including classes, and the # prefix means the instance
variable of whatever object is currently self. Inside an instance method definitions, self is an instance
of the class. But outside of that, just inside the class definition, self is the class object - so you defined
an instance variable named #a for the class object A, which none of the instances of A can get to directly.
Ruby does have a reason for this behaviour (class instance variables can be really handy if you know what
you're doing), but this is a more advanced technique.
In short, only initialize instance variables in the initialize method.
table = {
:a => 'test',
:b => 12,
:c => lambda { "Hallo" },
:d => def print(); "Hallo in test"; end
}
puts table[:a]
puts table[:b]
puts table[:c].call
puts table[:d].send( :print )
Well, the first line in your class calls a method that doesn't exist yet. It won't even exist after the whole class is loaded though, since that would be a call to the class method and you've only defined instance methods.
Also keep in mind that {0 => a()} will call the method a(), not create a reference to the method a(). If you wanted to put a function in there that doesn't get evaluated until later, you'd have to use some kind of Lambda.
I am pretty new to using callbacks in Ruby and this is how I explained it to myself using an example:
require 'logger'
log = Logger.new('/var/tmp/log.out')
def callit(severity, msg, myproc)
myproc.call(sev, msg)
end
lookup_severity = {}
lookup_severity['info'] = Proc.new { |x| log.info(x) }
lookup_severity['debug'] = Proc.new { |x| log.debug(x) }
logit = Proc.new { |x,y| lookup_sev[x].call(y) }
callit('info', "check4", logit)
callit('debug', "check5", logit)
a = ->(string="No string passed") do
puts string
end
some_hash = { 0 => a }
some_hash[0].call("Hello World")
some_hash[0][]

Resources