Mocha expects method - ruby-on-rails

So my situation is:
I have a 2 modules that have the same structure like that:
module Module1
class Config
def fee_rate
2
end
end
end
So, say, Module2 would have class Config with the method fee_rate, just with a different value (those are actually implemented in a rails engine, but it shouldn't matter)
and then my model can use either Module1 or Module2 to get the fee rate value like that:
def config
#config ||= "#{module_name.titleize}::Config".constantize.new
#config
end
def get_value
config.get_fee * some_other_value
end
What I'm trying to test is if get_fee function was called on the correct class:
"#{model.module_name.titleize}::Config".constantize.any_instance.expects(:get_fee).at_least_once
model.get_value
and on the line when I call get_value I get the following error - undefined method `*' for nil:NilClass. I'm completely lost now, so I'd appreciate any help and ideas.

By setting up an expectation for get_fee you are preventing the actual method call from happening. Because you haven't set a return value for the expectation, e.g. expects(:get_fee).at_least_once.returns(3) it is returning nil, hence the error message.
You may have more success by doing away with the expectation altogether and checking that the right type of config class is created, e.g.
model.get_value
assert_equal "#{model.module_name.titleize}::Config".constantize,
model.config.class

Related

How can I run a private method in a module in rails console?

I have an error in a private method in a helper file. The helper file looks something like below with module HxHelper. I want to run method_2 in rails console to recreate the error in my local system.
module HxHelper
def method_1{
"key_1": "#h.htype"
"key_2": "value_2"
+ method_2}
end
private
def method_2{
"key1": "value_1"}
end
In my controller file I define a new class and include the previous helper file. I have tried the following.
Created an object of my class as obj = Class.new and obj.method_1. I get an error undefined method type in method_1. hype is attribute in house table.
Tried HxHeleper::method_1: Error - method_1 is not defined in HxHelper module.
Defining method_2 as self: Doesn't work.
Can someone help me understand what I am doing wrong?
Assuming we can get around your syntax issues, the standard answer to 'how do I call a private method in Ruby?' is with .send(), as in obj.send(:private_method).
After you manually debug this, learn to write automated tests. Rails has exemplary, industry-leading support for them. The tests will take over the role of experimentation and investigation that you are currently abusing the console for.
You have some syntax errors in this example. You want to use commas at the end of the lines of your hash, you can't add two hashes together, you instead need to merge. Merging will take the receiver (the thing you're calling merge on) and override any values from the argument. Additionally, when using : in your hash, your keys end up being symbols, which means you don't need the quotes.
This would be the proper way to define the helper module.
module HxHelper
def method_1
{
key_1: "#h.htype",
key_2: "value_2",
}.merge(method_2)
end
private
def method_2
{
key1: "value_1",
}
end
end
Then you can use it like this:
class Test
include HxHelper
end
t = Test.new
t.method_1
This will return:
{:key_1=>"#h.htype", :key_2=>"value_2", :key1=>"value_1"}
If you call t.method_2, you get an error about calling a private method.
If method_2's hash had a key of key_1 instead, your return value would be:
{:key_1=>"value_1", :key_2=>"value_2"}
because the :key_1 from the argument overrode the one on the receiver Hash.
If you wanted to call that private method, you could do:
t.send(:method_2)
If you had a method that took arguments, you just add them after the symbol of the method name:
private
def test(num1, num2)
return(num1 + num2)
end
send(:test, 1, 2)
This would return 3

Override method (monkey patch?) on rails core

On this file:
...gems/actionpack-2.3.18/lib/action_controller/rescue.rb
Exists a method called local_request? inside module Rescue, that is contained in module ActionController, so its like this:
module ActionController
...
module Rescue
...
protected
...
# True if the request came from localhost, 127.0.0.1. Override this
# method if you wish to redefine the meaning of a local request to
# include remote IP addresses or other criteria.
def local_request?
....
I want to override that method in order to handle all requests as non-local, I tried with this (what I think is a monkey patch, not sure if the term is wrong)
module ActionController
module Rescue
protected
def local_request? #:doc:
false
end
end
end
It seems to work (that method return false), but when making a request I receive an error:
undefined method `call_with_exception' for ApplicationController:Class
That method exists in
module ActionController > module Rescue > module ClassMethods
1) If i'm overriding only one method why that got undefined? im deleting the other methods/modules inside the one i'm modifying?
2) How to and whats the right way to do this?
In rails 2.3.x Rails uses ruby's autoload method to load the modules that make up ActionController (see here: the file defining each module is only loaded when the constant is first accessed.
Because you are defining a constant of the same name, autoload will never get triggered (since as far as ruby is concerned it doesn't need to), so the rails provided code never gets loaded. You could instead do
ActionController::Rescue.module_eval do
def local_request?
false
end
end
Although as pointed out in the comments you can just define this on your controller - no need to do it this way.

How to create this model meta method?

I used to have the following model method, which I called upon using if #invitation.invite_expired? ...:
def invite_expired?
cycle_invite_sent_at < 2.hours.ago
end
Because I want to use this method for multiple expiration checks I have tried to create a "meta" method as follows:
def expired?(what)
check = send("#{what}_invite_sent_at")
check < 2.hours.ago #Also tried "self.check" but that made no difference.
end
I call upon this method using: if #invitation.expired?(cycle) .... However, now all sorts of tests fail with the message:
NameError: undefined local variable or method `cycle' for #<InvitationsController:0x0000000a5e8d50>
Does anyone see what I'm doing wrong here?
You should use it like:
if #invitation.expired?("cycle")
# some code here.
I assume this because undefined local variable or method 'cycle' raised in the controller code, it happens, when you try to use plain cycle instead of a string "cycle".

Reopening a namespaced class in ruby -- initialize overridden?

I've got a class in a namespace with a few methods
module Foo
module Bar
class Baz
def initialize(arg1, arg2, arg3)
# do stuff
end
def delete
File.delete(#path)
end
end
end
end
In my test environment, I don't want delete to delete any files, so in a TestHelper, I do this
class Foo::Bar::Baz
def delete
puts "no delete in test"
end
end
When I initialize this class this in my test, I get ArgumentError: wrong number of arguments (3 for 0). That is, the initialize method of Baz is gone. And to be sure, if I take a look at self in my test helper, there are no methods defined at all for Baz. It's been completely overridden by the class keyword.
I can make it work by using class_eval instead of class, i,e.
Foo::Bar::Baz.class_eval do
def delete
# etc
end
end
My question is, what is the difference? Why does the latter work but not the former?
I could be wrong, but I think you're accidentally breaking the autoloader. Here's what I think is happening in your working case (using .class_eval):
Something, somewhere, loads code that defines Foo::Bar (you'd be getting other errors if this wasn't happening)
Test code is parsed; explicitly requires TestHelper
TestHelper references Foo::Bar::Baz, which does not exist
autoloader finds and loads foo/bar/baz.rb
TestHelper runs class_eval and redefines #delete
Test code runs
And here's my guess at the non-working case:
Again, something, somewhere, loads code that defines Foo::Bar
Test code is parsed; explicitly requires TestHelper
TestHelper creates Foo::Bar::Baz, since it didn't already exist
Test code runs
Notice in the second case the autoloader was never triggered, so your actual class definition is never loaded.
I'm not sure the best way to solve this. You could do an explicit require in your test, or just reference the class in your helper before redefining it:
Foo::Bar::Baz # trigger autoloading before we muck with the definition
class Foo::Bar::Baz
def delete
puts "no delete in test"
end
end

NameError: undefined local variable or method `desired_preferences'

I have created a module with a method
module Adding_preferences
def desired_preferences
#preference = %w(motabilitySpecialist newCars bodyshop filter8 filter7).each do |selection|
#browser.label(:for, selection ).click
end
end
end
I have included this module into a class:
class Pages
include Adding_preferences
attr_accessor :browser, :preference
def initialize
#browser = Watir::Browser.new :ff
end
end
World do
Pages.new
end
I am calling this method in a Cucumber scenario
When /^I select a desired preference$/ do
desired_preferences
end
But at runtime I receive an error, "NameError: undefined local variable or method `desired_preferences'". Where am i going wrong?
When you include a module to a class you can use this method in the instance methods of this class. You cant call the included method in a View that displays the data from the model that includes the module. For me it looks like you just dont use the desired_preferences method in an instance method.
Please show us the peace of code you try to call the method if this still doesnt help you out.
// The naming of the Module is not conventional. You should call it module AddingPreferences isntead ofmodule Adding_preferences and the file should be named adding_preferences.rb then try to include AddingPreferences
It's a good idea for you to spend some time getting more familiar with Ruby's Class/Module/Object/Method inheritance model, because the way you're structuring your code there is a little bit messy.
However, a simple thing to try (and I'm not going to guarantee that it will work flawlessly) is the following modifications:
Assign your instantiated Pages class to a class instance variable:
World do
#page = Pages.new
end
...and then use that instance variable in your step definition...
When /^I select a desired preference$/ do
#page.desired_preferences
end
I hope that helps!

Resources