Call methods from another class. How it works? - ruby

The method defined in a different class and I don't understand how methods are associated with each other
class Route
attr_reader :stations #getter method
end
class Train
attr_accessor :route #getter and setter method
def show_stations
route.stations # How it works?
end
end
route = Route.new
train = Train.new
train.route = route
train.show_stations

When a method call has an explicit receiver, it doesn't matter in what context you call it from. All that matters is that the receiver has that method.
The context of method call route.stations does not matter. All that matters is whether the receiver route has the method stations. Since route is a Route instance, it does have the method stations, as defined by attr_reader :stations.

Related

Puppet: Is it possible to call an instance method in a ruby template (era) that was returned from a custom function in a manifest?

There is a custom function that returns a class instance.
Puppet::Functions.create_function(:'my_custom_function') do
dispatch :make do
end
class Sample
attr_reader :value
def initialize( value )
#value = value
end
def to_s()
'<Sample %d>' % [ value ]
end
end
def make()
Sample.new(1)
end
end
ie:
class myclass {
$data = my_custom_function()
}
Is it possible to use the $data as a complex type in an ERB template?
Due to the "to_s" defined for the class this works:
<%= #data %>
yields
<Sample 1>
but it doesn't appear possible to access any of the instance methods (ie: #data.value)
When trying to access .value, the following error is typical:
Detail: undefined method `value' for #<Puppet::Pops::Loader::RubyFunctionInstantiator::Sample:0x7ace1824>
Is accessing class methods at all possible? If so, how?
Thanks.

What is the meaning in single model instance in RetrieveAPIView in drf

What is the meaning of single model instance in RetrieveAPIView in Django REST framework.And how can we use? And will it look?
As my understanding:
single model instance: Example we use RetrieveAPIView. If we read the method that handle requests to that class, that is:
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)
We can see self.get_object(), it will build a Queryset to get object instance from our model class using method get(), or rather using get_object_or_404(). As we know, get() will only take 1 object instance, or it called single model instance.
Example Book.objects.get(id=10).
For more detail, we can open this link. Start from def retrieve then read also get_object().
Likewise on DestroyAPIView and UpdateAPIView.
collection of model instances: When build a Queryset, it using all() or filter(), according to what we wrote in queryset = .... or we override in def get_queryset. Example: Book.objects.all(). See this link and read def list.
CMIW.

Call private class method from private instance method

I am new to Ruby and came from C# world. In C# it is legal to do stuff like this:
public class Test
{
public void Method()
{
PrivateMethod();
}
private void PrivateMethod()
{
PrivateStaticMethod();
}
private static void PrivateStaticMethod()
{
}
}
Is it possible to do something similar in Ruby?
A little bit of context: I have a Rails app... One of the models has a private method that sets up some dependencies. There is a class method that creates initialized instance of the model. For legacy reasons there are some instances of the model that are not initialized correctly. I added an instance method that initializes 'uninitialized' instances where I want to do same initialization logic. Is there a way to avoid duplication?
Sample:
class MyModel < ActiveRecord::Base
def self.create_instance
model = MyModel.new
model.init_some_dependencies # this fails
model
end
def initialize_instance
// do some other work
other_init
// call private method
init_some_dependencies
end
private
def init_some_dependencies
end
end
I tried to convert my private method to a private class method, but I still get an error:
class MyModel < ActiveRecord::Base
def self.create_instance
model = MyModel.new
MyModel.init_some_dependencies_class(model)
model
end
def initialize_instance
# do some other work
other_init
# call private method
init_some_dependencies
end
private
def init_some_dependencies
MyModel.init_some_dependencies_class(self) # now this fails with exception
end
def self.init_some_dependencies_class(model)
# do something with model
end
private_class_method :init_some_dependencies_class
end
First let me try to explain why the code does not work
class MyModel < ActiveRecord::Base
def self.create_instance
model = MyModel.new
# in here, you are not inside of the instance scope, you are outside of the object
# so calling model.somemething can only access public method of the object.
model.init_some_dependencies
...
end
...
You could bypass private calling of the method with model.send :init_some_dependencies. But I think in this case there is probably better solution.
I would guess that init_some_dependencies probably contain more business / domain logic rather than persistence. That's why I would suggest to pull out this logic into a "Domain Object" (or some call it Service Object). Which is just a plain ruby object that contain domain logic.
This way you could separate persistence logic to ActiveRecord and the domain logic to that class. Hence you will not bloat the ActiveRecord Model. And you get the bonus of testing
the domain logic without the need of ActiveRecord. This will make your test faster.
You could create a file say `lib/MyModelDomain.rb'
class MyModelDomain
attr_accessor :my_model
def initialize(my_model)
#my_model = my_model
end
def init_some_dependencies
my_model.property = 'some value example'
end
end
Now you could use this object say something like this
class MyModel < ActiveRecord::Base
def self.create_instance
model = MyModel.new
domain = MyModelDomain.new(model)
domain.init_some_dependencies
domain.my_model
end
def initialize_instance
# do some other work
other_init
domain = MyModelDomain.new(self)
domain.init_some_dependencies
end
end
You might also want to move the initialize_instance if you think it's necessary
Some resource that go deep into this pattern:
http://railscasts.com/episodes/398-service-objects
https://www.destroyallsoftware.com/screencasts/catalog/extracting-domain-objects
You can use
model = MyModel.new
model.send :init_some_dependencies
to bypass method visibility checks.
In C# it is legal to do stuff like this:
public class Test
{
public void Method()
{
PrivateMethod();
}
private void PrivateMethod()
{
PrivateStaticMethod();
}
private static void PrivateStaticMethod()
{
}
}
Is it possible to do something similar in Ruby?
Yes:
class Test
def method
private_method()
end
def self.greet
puts 'Hi'
end
private_class_method :greet
private
def private_method
self.class.class_eval do
greet
end
end
end
Test.new.method
Test.greet
--output:--
Hi
1.rb:23:in `<main>': private method `greet' called for Test:Class (NoMethodError)
But ruby doesn't strictly enforce privacy. For instance,
class Dog
def initialize
#private = "secret password"
end
end
puts Dog.new.instance_variable_get(:#private)
--output:--
secret password
ruby gives you the freedom to access private things with a little bit of extra effort:
Test.new.method
Test.class_eval do
greet
end
--output:--
Hi
Hi
In ruby, a private method only means that you cannot explicitly specify a receiver for the method, i.e. there can't be a name and a dot to the left of the method. But in ruby, a method without a receiver implicitly uses self as the receiver. So to call a private method, you just have to create a context where self is the correct receiver. Both class_eval and instance_eval change self inside the block to their receiver, e.g.
some_obj.instance_eval do
#Inside here, self=some_obj
#Go crazy and call private methods defined in some_obj's class here
end
You can apply those rules to this situation:
(ahmy wrote:)
First let me try to explain why the code does not work
class MyModel < ActiveRecord::Base
def self.create_instance
model = MyModel.new
# in here, you are not inside of the instance scope, you are outside of the object
# so calling model.somemething can only access public method of the object.
model.init_some_dependencies # this fails
... end ...
"Context this" and "scope that"--what a headache. All you have to remember is: you cannot call a private method with an explicit receiver. The method init_some_dependencies was defined as a private method--yet it has "model." written to the left of it. That is an explicit receiver. Bang! An error.
Here is a solution:
class MyModel
def self.create_instance
#In here, self=MyModel
puts self
model = MyModel.new
model.instance_eval do #Changes self to model inside the block
#In here, self=model
init_some_dependencies #Implicitly uses self as the receiver, so that line is equivalent to model.init_some_dependencies
end
end
private
def init_some_dependencies
puts "Dependencies have been initialized!"
end
end
MyModel.create_instance
--output:--
MyModel
Dependencies have been initialized!
Or as ahmy and LBg pointed out, you can use Object#send() to call private methods:
class MyModel
def self.create_instance
model = MyModel.new
model.send(:init_some_dependencies, 10, 20)
end
private
def init_some_dependencies(*args)
puts "Dependencies have been initialized with: #{args}!"
end
end
MyModel.create_instance
--output:--
Dependencies have been initialized with: [10, 20]!
acturally, it surely does.
Ruby's some OO strategies(private & public keywords etc.) comes from C++, so you can get almost same usage.

get_queryset method and ViewSets in django rest framework

I am doing exactly as the example states
here is my method
class FeedViewSet(viewsets.ModelViewSet):
model = Feed
serializer_class = FullFeedSerializer
def get_queryset(self):
user = request.user
queryset = Feed.objects.get_nearby(user)
return queryset
when i execute it, it says request not defined .. which actually isn't. the example at the rest framework's site also haven't defined request. what am i doing wrong?
The request object is available (on either REST framework's class based views, or Django's standard class based views) as self.request. You're missing the self. part of that.

How can I tell if a method is read-write, read-only, or write-only, via introspection?

I am coming from Java, and want to know if I can 'set' an instance variable for an object using introspection.
For example, if I have the following class declaration, with the two instance variables, first_attribute and second_attribute:
class SomeClass
attr_accessor :first_attribute
attr_reader :second_attribute
def initialize()
# ...
end
end
I want to be able to get the instance methods, presumably by calling SomeClass.instance_methods and know which of those instance methods are read/write vs. just read-only.
In Java I can do this by:
PropertyDescriptor[] properties = PropertyUtils.GetPropertyDescriptors(SomeClass);
for (prop : properties) {
if (prop.getWriteMethod() != null) {
// I can set this one!
}
}
How do I do this in Ruby?
There's not really anything built-in like the Java property stuff, but you can do it pretty easily like this:
self.class.instance_methods.grep(/\w=$/)
Which will return the names of all the setter methods on the class.

Resources