May be a mistake in Metaprogramming Ruby [closed] - ruby

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I am reading Metaprogramming Ruby by Paolo Perrotta and I must say there is a mistake in the book,the following is the ruby code from page 70 of this book and I will past the code here again
class Computer
def initialize(computer_id, data_source)
#id = computer_id
#data_source = data_source
end
def self.define_component(name)
define_method(name) {
info = #data_source.send "get_#{name}_info" , #id
price = #data_source.send "get_#{name}_price" , #id
result = "#{name.to_s.capitalize}: #{info} ($#{price})"
return "* #{result}" if price >= 100
result
}
end
define_component :mouse
define_component :cpu
define_component :keyboard
Computer.define_component is a class method like static method in Java. What Java told us is that a static method can never access an instance attribute or an instance method without an object. So,define_component method must not use invoke define_method,which is an instance method. Logically speaking,class method was invoked before object have been created,so there is no way that #data_source and #id can be initialized(it have bean created). But here define_component invoked define_method without an instance. Is that correct?

You are missing the point slightly. The define_method will indeed not have access to the instance variables, but define_method when called on class will actually create a regular instance method. The name of this method is the parameter to define_method and the body of this new instance method is the block passed.
So define method will not actually execute the code (it can't). It will simply create a new method that can be called upon to execute the code.
I hope I got the point across.

Well, your thinking is corrupted by java. It is a strict language with strict rules. Ruby is more powerful/flexible.
def self.define_component(name)
# class scope here
define_method(name) {
# instance scope here. You can use instance-level instance variables.
}
end
define_component method defines an instance method on the class. In the body of that instance method you, naturally, can use instance variables.

Ruby doesn't have static methods. The only similarity between Ruby class methods and Java static methods is that they can both be called on classes.
In Ruby, classes are objects — they are instances of a class named Class, and they can have their own instance variables just like other object can. A class method isn't like a static method in Java — it's a singleton method of the class. You can define instance-specific methods on any object in exactly the same way.

Related

Ruby analog of "this" (access class instance from inside) [duplicate]

This question already has answers here:
Ruby equivalent to PHP's $this
(2 answers)
Closed 4 years ago.
In many languages there is a concept of this available from inside an object (e.g. class instance). Consider this generic pseudocode:
class Foo {
int x;
constructor() {
this.x = 10;
}
}
Here this provides access to the object from inside. It can be useful in numerous ways.
Now, I can't find how we can access this from inside Ruby class. I see that properties are accessible by # prefix and methods are accessible by their names, but these are just parts of an instance, not an instance itself. So the question is: how we access a full Ruby object from inside of that object?
In ruby, you should use self instead of this, is the equivalent.
Now, we have a difference between a instance and a class method.
See the example:
class Person < ActiveRecord::Base
def self.class_method_example
return self
end
def instance_method_example
return self
end
end
In the first case, we can compare the class with the result:
Person.class_method_example == Person # this returns true
In the second, we can only call the method with a Person instance:
Person.first.instance_method_example == Person.first # this returns true
UPDATE
In second example, i'am presuming the extend of ActiveRecord::Base to use the first method
The method you're looking for is self:
https://blog.honeybadger.io/ruby-self-cheat-sheet
https://airbrake.io/blog/ruby/self-ruby-overview

How does Ruby make #initialize private?

I understand that Ruby's #initialize method is private. However, what stumps me is how Ruby makes the method private.
We normally define classes like this:
class Cat
def initialize(name)
#name = name
end
def say_name
puts #name
end
end
where #initialize seems to be defined publicly alongside #say_name. How does Ruby manage to make #initialize private after the class definition?
Yukihiro Matsumoto (the inventor of Ruby) has said:
#initialize is, by its design, supposed to be called only from within #new to separate per object/class initialization from the #new, thus you don't have to redefine #new. When you need/want to redefine #new, it's a sign of a bad design, I believe.
One of the reason #initialize being private is to tell you bad design.
So in summary it's a built in feature of Ruby that #initialize is automatically private and it's so developers won't easily call it outside of the .new class method.
Very interesting question! I researched it and found some interesting things about Ruby, though I did not find the exact answer you're looking for.
initialize is a private instance method that is meant to be redefined on most objects. It comes from BasicObject, the Ruby class from which all objects and classes inherit.
Any new class you create in Ruby will have a private instance method called initialize:
class Q ; end
Q.private_instance_methods.include?(:initialize)
=> true
That instance method is inherited from BasicObject#initialize:
q = Q.new
q.method(:initialize)
=> #<Method: Q(BasicObject)#initialize>
And the method itself is not defined in Ruby, it comes from the C source of the language:
q.method(:initialize).source_location
=> nil
This is what that looks like in the Ruby source code (object.c file):
rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_dummy, 0);
rb_obj_dummy is basically a no-op function. Which makes sense because the expectation is that you'll override initialize with your own implementation code in your class.
All that said, your original question was about why initialize doesn't become a public method when you define it in the public space in your class definition. I don't know. Normally if you do that for any other method it will become a public method:
class Q
private
def my_private_method() "private" end
end
Q.new.my_private_method
NoMethodError: private method `my_private_method' called for #<Q:0x007fc5ea39eab0>
class Q
def my_private_method() "now i'm a public method" end
end
Q.new.my_private_method
=> "now i'm a public method"
So I guess somewhere else deep in the source code defining a method named "initialize" is handled differently from other methods. I couldn't find it, but maybe someone else can.

passing child class method as function argument in ruby

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.

Call method in same class [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I'm new to ruby and I was wondering the following, can I call a method in the same class such as:
class myClass
$myVar = inClass
def inClass
#value = (gets data from db)
end
end
If there is a way to do this, can someone please help me?
You can do as below
class MyClass
def in_class
#value = (gets data from db)
end
def call_inclass
$my_var = in_class # don't use global variable.
end
end
Create a new instance method call_inclass and call the required class in_class from there. Your one will not work, as in_class is an instance method, and within class.. end body self is set to that class. Thus $myVar = in_class will simply thorw an error as no method error. Because $myVar = in_class it will be interpreted implicitly as $myVar = self.in_class, where self is MyClass. in_class is not a method of MyClass, rather an instance method of instances of MyClass.
Thus wrapped the method call to in_class inside another instance method, like here call_inclass.
Another way is make in_class as a singleton method of MyClass. Then it will work.
class MyClass
# again don't use global variable, rather use
# class instance variable, #my_var
$my_var = in_class
def self.in_class
#value = (gets data from db)
end
end

What does `def self.function` name mean?

Can anyone explain to me what the meaning of adding self to the method definition is? Is it similar to the this keyword in java?
Contrary to other languages, Ruby has no class methods, but it has singleton methods attached to a particular object.
cat = String.new("cat")
def cat.speak
'miaow'
end
cat.speak #=> "miaow"
cat.singleton_methods #=> ["speak"]
def cat.speak creates a singleton method attached to the object cat.
When you write class A, it is equivalent to A = Class.new :
A = Class.new
def A.speak
"I'm class A"
end
A.speak #=> "I'm class A"
A.singleton_methods #=> ["speak"]
def A.speak creates a singleton method attached to the object A. We call it a class method of class A.
When you write
class A
def self.c_method
'in A#c_method'
end
end
you create an instance of Class(*). Inside the class definition, Ruby sets self to this new instance of Class, which has been assigned to the constant A. Thus def self.c_method is equivalent to def cat.speak, that is to say you define a singleton method attached to the object self, which is currently the class A.
Now the class A has two singleton methods, that we commonly call class methods.
A.singleton_methods
=> ["c_method", "speak"]
(*) technically, in this case where A has already been created by A = Class.new, class A reopens the existing class. That's why we have two singleton methods at the end. But in the usual case where it is the first definition of a class, it means Class.new.
In ruby self is somewhat similar to this in java, but when it comes to classes its more like the keyword static in java. A short example:
class A
# class method
def self.c_method
true
end
# instance method
def i_method
true
end
end
A.c_method #=> true
A.i_method #=> failure
A.new.i_method #=> true
A.new.c_method #=> failure
Update: Difference between static methods in java and class methods in ruby
Static methods in Java have two distinct features that makes them different from instance methods: a) they are static, b) they are not associated with an instance. (IOW: they really aren't like methods at all, they are just procedures.) In Ruby, all methods are dynamic, and all methods are associated with an instance. In fact, unlike Java where there are three different kinds of "methods" (instance methods, static methods and constructors), there is only one kind of method in Ruby: instance methods. So, no: static methods in Java are completely unlike methods in Ruby. – Jörg W Mittag 1 hour ago
When declaring a method, the self of the declaration is the declaring class/module, so effectively you are defining a class method. For the client, this works similar to a static method in java. The client would call the method on the class instead of an instance: MyClass.method
Here you can find some more details on class and instance methods.
EDIT: While the self keyword is akin to the this keyword in java, the effects of using self for class method declaration are similar to the effect of using the static keyword in java. The similarity is that static methods in java, like class methods in ruby are accessed using the class object iself instead of an instance of the class.
Please note that static does not stand for the opposite of dynamic. The choice of the name for this keyword is questionable (probably inherited from C) and rather should have been called perClass or similar to better reflect the meaning. The technical meaning is that all static members exist only once for each classloader.

Resources