What's Ruby's equivalent of cached_property in python? - ruby

Basically, I have a Ruby class which has a property to make expensive HTTP calls to get some value, I need the value to be cached, so next time I access the property I don't have to call HTTP again.
http://pydanny.com/cached-property.html
https://wiki.python.org/moin/PythonDecoratorLibrary#Cached_Properties
Is there a Ruby version for this?

Assuming the instance of your class persists, you would simply need to memoize the result.
class Foo
def http_response
#_http_response ||= begin
# your slow I/O bound code here
end
end
end
Unless the result of that block is falsy, it won't be executed again. There are several variations on this concept, for example:
class Foo
def http_response(skip_cache = false)
return #_http_response unless skip_cache || !#_http_response
#_http_response = fetch_http_response
end
private
def fetch_http_response
# your slow I/O bound code here
end
end

Related

Can you instantialise `Data` class's data inside Ruby?

When trying to use an instance method of a Ruby-C-Class:
RubyCClass.new.someMethod()
Ruby is raising the following error:
Error: wrong argument type RubyCClass (expected Data)
Is there any way I can instantiate the class properly such that RubyCClass is instantiated to the extent that someMethod will begin execution? In other words, is there a way I can inject Data into RubyCClass such that someMethod begins execution?
I'm not sure where that error is being generated; is it when the engine is evaluating the value returned by your Ruby code?
If so, you could do whatever you want to do, and then return a dummy Data object:
RubyCClass.new.someMethod()
# do other things, then:
Data.new
# or whatever it is you do to create a Data instance;
# as the final value in your code it will be returned
[Note: This answer was posted when the question was drastically different; it has been edited since then.]
I'm not completely sure if your question, but I think your main problem as that you are using method instead of public_send. (And, by the way, you can get a list of an object's public methods by calling object.public_methods, in case that's helpful.)
Here is some code that illustrates what might work for you:
#!/usr/bin/env ruby
class MethodAccessibility
attr_reader :accessibles, :inaccessibles
def initialize
#accessibles = []
#inaccessibles = []
populate_data
end
def method_accessible?(object, method_name, *args)
begin
object.public_send(method_name, args)
true
rescue Exception => e
e.to_s != "Error: This method cannot be used within the User Interface"
end
end
def add_to_appropriate_array(object, method_name, *args)
accessible = method_accessible?(object, method_name, args)
(accessible ? accessibles : inaccessibles) << method_name
end
def populate_data
object = # create the object on which to call the methods
add_to_appropriate_array(object, :method1, [:arg1, :arg2]) # for examples
add_to_appropriate_array(object, :method2, [])
# ...
end
end
ma = MethodAccessibility.new
ma.accessibles # do something with this array, or the `inaccessibles` array

Ruby using self in accessor method causes SystemStackError

I don't get this, when I try to run below code, I am getting
employee.rb:55:in `hourly_wage=': stack level too deep (SystemStackError)
class HourlyEmployee < Employee
attr_reader :hourly_wage, :hours_per_week
def hourly_wage=(hourly_wage)
self.hourly_wage = hourly_wage
end
def hours_per_week=(hours_per_week)
self.hours_per_week = hours_per_week
end
def print_pay_stub
print_name
pay_for_period = (hourly_wage) * (hours_per_week) * 2
formatted_pay = format("$%.2f", pay_for_period)
puts "Pay for this period: #{formatted_pay}"
end
end
Isn't this basically the same in Java where I use the this keyword in the setter method?
If I replaced the def with then everything works fine.
def hourly_wage=(hourly_wage)
#hourly_wage = hourly_wage
end
Sorry, just started picking up Ruby
you can imagine that hourly_wage= is a method name
your code:
def hourly_wage=(hourly_wage)
self.hourly_wage = hourly_wage
end
if you replace the name hourly_wage= with assign, it'll become:
def assign(hourly_wage)
self.assign(hourly_wage)
end
you recursively call yourself without a break-point, so it raise stack level too deep exception.
You are recursively calling hourly_wage= in hourly_wage=, with no termination condition, so you are recursing infinitely. Since Ruby does not have Proper Tail-Recursion, you will at some time run out of stack space.
Isn't this basically the same in Java where I use the this keyword in the setter method?
Yes, it is exactly the same as this equivalent Java code:
void setHourlyWage(BigDecimal hourlyWage) {
this.setHourlyWage(hourlyWage);
}
This will have the exact same result: a stack overflow.
If I replaced the def with then everything works fine.
def hourly_wage=(hourly_wage)
#hourly_wage = hourly_wage
end
This is something completely different. Here you are not recursively calling hourly_wage= but instead simply assigning to an instance variable ("field" in Java jargon).

Lazy object in ruby

How can I create an opbjet that's totally lazy by itself? I have a block, and I want to pass around (as a dependency) the "current value" (at call time) of the block instead of the value at dependency injection time.
I can't actually pass around a lambda because all the services expect an actual object, so they won't send :call to them, just access them.
This (oversimplified) example might clarify the situation:
class Timer
def initialize(current_time)
#current_time = current_time
end
def print_current_time
print #current_time
end
end
class Injector
def current_time
# a lazy object that when accessed actually calls the lambda below
# every single time.
end
def current_time_lazy
-> { Time.now }
end
def instantiate(class_name)
# search for the class, look at the constructor and
# create an instance with the dependencies injected by
# name
# but to be simple
if class_name == "Timer"
Timer.new(current_time)
end
end
end
timer = Injector.new.instantiate("Timer")
timer.print_current_time # => some time
sleep 2
timer.print_current_time # => some *different* time
The actual situation implies passing around the current_user but depending on the situation the current user might change after those values are injected.
I would really appreciate any suggestion (even if for now I will carefully sort the dependency injection code so this doesn't happen, but I think it's pretty fragile)
This should help :
class Timer
def initialize(current_time)
#current_time = current_time
end
def print_current_time
puts #current_time
end
end
class LazyMaker < BasicObject
def self.instantiate(class_name, lambada)
if class_name == 'Timer'
::Timer.new(new(class_name, lambada))
end
end
def initialize(class_name, lambada)
#lambada = lambada
end
def method_missing(method, *args)
#lambada.call.send(method, *args)
end
end
timer = LazyMaker.instantiate('Timer', -> { Time.now })
timer.print_current_time # some time
sleep 2
timer.print_current_time # some other time
I'm trying to use delegation to implement it, so that I can call the block first, get a new object and redirect the method call to it. Why this way ? Because basically, accessing an object to do something means to call a method on it. For instance, in print #current_time, it sends #current_time.to_s.
But since almost all objects will have a few methods inherited from standard base classes in Ruby like Object, LazyMaker also has methods like to_s. So I thought of making just the LazyMaker inherit from BasicObject, which is a blank class. So almost all of the methods get delegated.
But yeah, there might be another way to do this.

Delegation in Ruby

I have a class Klass, and its constructor accepts an argument. We should be able to call methods on this object that are not defined in Klass.
We can chain multiple methods, but in the end, we have to use Klass#result to get the result like:
Klass.new(5).pred.pred.result
and the output here should be 3. I tried using method_missing in Klass and using send on the object's class, but that would have worked without the result method that I have to use. Can someone explain how this can be done with delegation?
You could do something like this:
class Klass
def initialize(number)
#number = number
end
def result
#number
end
def method_missing(method_name, *arguments, &block)
if #number.respond_to?(method_name)
#number = #number.method(method_name).call(*arguments, &block)
return self
else
super
end
end
def respond_to_missing?(method_name, include_private = false)
# be sure to implement this...
end
end
puts Klass.new(5).pred.pred.result # => 3
But it's problematic. In this particular example, since #pred returns a new object (it doesn't modify the object it was called on), we have to reassign the instance variable to the result. It works for pred and other methods that return new Integers, but some methods on Integer don't return an Integer (e.g. Integer#even). In this case you'd get this sort of behavior:
puts Klass.new(4).even?.result # => true
Depending on your particular situation, that might be what you're after. Or, it might be that in your situation all methods the object being delegated to mutate that object, rather than return new instances of the object, in which case the reassignment isn't needed.
I don't think you can use Ruby's existing Delegator and SimpleDelegator constructs, because the only way you can chain the final #result call onto the end is if every delegated call returns the instance of Klass. Using those existing constructs would cause delegated calls to return their normal return values, and the chaining would then be on whatever objects those return values return. For example, using the above code, you'd see this behavior:
puts Klass.new(5).pred.pred.class # => "Klass"
Using SimpleDelegator, you'd see this behavior
require 'delegate'
class Klass2 < SimpleDelegator
# Klass2 methods...
end
puts Klass2.new(5).pred.pred.class # => "Fixnum"
Hope that helps.

Using define_method in a loop to create methods in Ruby (Through Selenium Webdriver)

I'm trying to create a method to dynamically do the following: (as I will have to implement this on about 30 different sets of sub-classes)
def t1
FooT1.new
end
def t2
FooT2.new
end
def t3
FooT3.new
end
Where there will be 2 variables in the method generation, the tab number(t1...tx) and the name of the class (Foo)
I tried the following, but I'm new to Ruby and can not get this working.
def method_generator(num_tabs, class_name)
1.upto(num_tabs) do |i|
define_method("t#{i}") do
"#{class_name}_t#{i}".new
end
end
end
Then call it in the sub-class like so:
method_generator(3, "Bar")
I'm aware I'm probably quite far off in implementing this, so any help is appreciated.
Just do as below :
def method_generator(num_tabs, class_name)
1.upto(num_tabs) do |i|
class_name.send(:define_method,"t#{i}") do
"#{class_name}_t#{i}".new
end
end
end
Module#define_method is a private method, thus you can't call it on the class_name like class_name.define_method(:name) do ..end, as private method call not allows explicit receiver. But to do so Object#send will help you, as this method is here for this kind of scenarios, where you can't call private method by explicit receiver.
Lets verify with an example, if this tricks works or not.
class Foo;end
def method_generator(num_tabs, class_name)
1.upto(num_tabs) do |i|
class_name.send(:define_method,"t#{i}") do
"#{class_name}_t#{i}".new
end
end
end
method_generator(3,Foo)
Foo.instance_methods(false)
# => [:t1, :t2, :t3] # see here 3 instance methods has been created of class Foo

Resources