I am having a very strange problem regarding method dispatch to the wrong class using Minitest.
I am helping maintain the dnsruby library (https://github.com/alexdalitz/dnsruby), and we have a particular test that intermittently fails (https://github.com/alexdalitz/dnsruby/blob/master/test/tc_resolv.rb#L56).
By setting a breakpoint in pry, I discovered that when it fails it is using the getname method on the internal Ruby Resolv class rather than the Dnsruby::Resolv class specified in the code. Both ::Resolv and Dnsruby::Resolv seem to point to the Ruby internal Resolv class:
[1] pry(#<TestResolv>)> ::Resolv.object_id
=> 70320518250220
[2] pry(#<TestResolv>)> Dnsruby::Resolv.object_id
=> 70320518250220
The error does not occur when the test is run on its own (ruby test/tc_resolv.rb). When combined with other tests (using ruby test/ts_online.rb and modifying its list of test files that are run), it often fails but sometimes not. The only factor I have found that seems to be correlated with the failure is the amount of test code that is run; the more tests are run, the more likely it is to fail.
When the test succeeds, ::Resolv is not even defined:
[1] pry(#<TestResolv>)> ::Resolv.object_id
NameError: uninitialized constant Resolv
I searched our codebase for require 'resolv' but did not find it. Perhaps another library we're using is requiring it. Even so, though, shouldn't the Dnsruby:: in Dnsruby::Resolv specify our customized Resolv class?
How can we fix this?
The problem was solved by removing an include Dnsruby in the top level that should not have been there. (Thanks to Ruby community member https://github.com/matt-glover for spotting this!)
More detail is at the Github issue at https://github.com/alexdalitz/dnsruby/issues/112, and the fix is in the pull request at https://github.com/alexdalitz/dnsruby/pull/121/files.
One thing that confuses me...I would have expected that include to result in the Dnsruby::Resolv class being pulled into the top level, but it seems that the reverse happened.
Related
I'm trying to create a gem, that wraps some external API calls, and I want to use a gem called 'api-blueprint'
I already added as a dependency on my gemspec file
spec.add_runtime_dependency 'api-blueprint'.
and now I want some of my classes to inherit from it
module MyGem
class Request < ApiBlueprint::Model
... code ...
end
end
And I get an error
NameError:
uninitialized constant MyGem::ApiBlueprint
And I'm not sure how can I inherit from a dependency without appending my gem name to the namespace. I also tried without wrapping it inside a module, but I get the same issue, albeit without MyGem namespace.
I used this gem inside a rails app, with the same use without problems, but now I need to refactor that logic out of the rails app into a gem.
I also tried to require both as api_blueprint and api-blueprint the latter returning this error
Failure/Error: require "api-blueprint"
ArgumentError:
wrong number of arguments (given 2, expected 0)
and the former just returning a LoadError.
I'm not sure what seems to be the issue here, do I need to include elsewhere besides the gemspec file? Note that I also use spec.add_dependency but I got the same issues. I'm a bit lost here, this is my first go at a rubygem
Thanks for the attention :)
And I'm not sure how can I inherit from a dependency without appending my gem name to the namespace.
You don't need to do that. You're just being confused by a misleading error message.
In ruby, constant lookups are first attempted inside the module and then in the global namespace.
So in other words, this code:
module MyGem
class Request < ApiBlueprint::Model
is first trying to find the constant: MyGem::ApiBlueprint::Model, and (if that fails), it then tries to find the constant: ApiBlueprint::Model. If that fails too, it uses the first error message, which is what you're seeing.
To prevent the confusing error message (although this alone won't fix the actual problem!!), you can explicitly tell the interpreter to only look for the constant in the global namespace:
module MyGem
class Request < ::ApiBlueprint::Model
Failure/Error: require "api-blueprint"
ArgumentError:
wrong number of arguments (given 2, expected 0)
You'll need to give us more context on that error. What's the stack trace? What method is being called with 2 arguments instead of 0?
As far as I can tell, adding this require statement should be all you need to do.
My Ruby Minitest is failing with an error like this:
<"undefined method `Error' for Api:Module">
It is not actually a method that is missing, it is a class:
class Api::Error
This class is defined in lib/api/error.rb.
I tried adding this line to config/environment.rb in my rails 2 application:
config.autoload_paths += %W( #{RAILS_ROOT}/lib )
It does nothing. I do not know where or if RAILS_ROOT is defined (is it a standard rails 2 variable?), but I copied it from a commented out line in the existing source code.
How can I make sure the class is loaded or find where it is not included? The Api::Error subclasses are raised in many files, and I don't want to edit them all. Because the class cannot be found, the stacktrace does not list the place where the real raise occurs. Stepping through code using pry is not working, because as soon as I get to the "get" method in a Webservice mock, I can't step in.
Once I found where the exception was being raised, I experimented.
This is how the code was originally, which caused the problem:
raise Api::Error #p4_client
This is the change I made:
raise Api::Error.new(#p4_client)
Explicitly calling the constructor with new rather than letting the raise logic in Ruby do it solved the problem.
This logic without the explicit call worked fine in 1.8.7, but fails in 1.9.3.
Everything is delegated through layers of Actionpack.
I'm writing a new rspec test case using Capybara (SitePrism actually, which uses Capybara) and I've run into an apparently known issue: https://github.com/jnicklas/capybara/issues/1396. Essentially, due to a change in one or the other, RSpec and Capybara now both have methods named all, and when I try to use SitePrism to find a group of elements or SitePrism sections, Capybara invokes the wrong method and returns something of the type RSpec::Matchers::BuiltIn::All rather than the expected array of Capybara or SitePrism objects.
For some reason, all my old tests, including many with very similar usage of sections and elements constructs, work perfectly fine. I'm having a really hard time finding differences between them that would account for one failing and the other succeeding. I briefly tried rolling back either Capybara or RSpec to just try to make the problem go away for the moment, but it seemed silly, trying to pinpoint when the problem was introduced, when existing test cases that have been running every day never broke.
Can anyone advise me on why one works and the other fails? Here is what these two test cases have in common:
Both spec files require the same spec_helper.rb file.
The spec_helper.rb file has both require rspec and require capybara.
Each spec file uses require_relative to require a page object used in each test.
Each page object file has a sections :table_rows, <SECTION CLASS>, <ROW CSS> declaration. They may have different names, classes, and CSS Selectors, but they're the same basic construct.
In each spec file, methods are invoked on the page objects that reference table_rows.
Referencing table_rows in one of these older test cases works just fine, but I'm getting the name collision error in the new test case. Anyone know why that might be, so I can fix the new test case?
Failing that, does anyone know how I can separate things so that the page object requires capybara but not rspec and the spec file requires rspec but not capybara to prevent the collision? I don't know much about Ruby package management, but it seems like in order to run an rspec test case that uses a page object, it's all going to be mixed together. I'm not sure of a way to avoid requiring them both.
Failing that, does anyone know which versions of either of these two packages I could theoretically use to avoid the issue? I did experiments with rspec 3.2 and capybara 2.4, and neither seemed to work, and I gave up there, because I remembered that no matter how far back in time I go, the test cases I've already written were working fine, and it just seemed silly to try to solve it this way.
Require capybara after Rspec or always call page.all rather than just all
Not the best approach, but you can monkey patch the SitePrism::Page class. Here you replace 'all' by 'page.all':
SitePrism::Page.class_eval do
def find_all(*find_args)
page.all(*find_args)
end
end
I've stumbled upon the following piece of code in an Rspec test and I must say I more or less figured out what it does but I can't find relevant sources to prove it. Please point me to a gem or docs that describe:
describe SomeModule::Salesforce::Lead do
before do
SomeModule::Salesforce::Lead.any_instance.expects(:materialize)
end
...
end
It seems that for :each example in this spec it sets expectation on any instance of the class described above to receive a call to :materialize method AND it actually redefines the method to do nothing . The last part seems crucial because it avoids connecting to SalesForce in test environment but I can't find confirmation for this.
any_instance is documented under Working with Legacy code
You are correct in that it both sets an expectation and stubs out the original method on any given instance of a class.
Previous versions of RSpec accomplish this by monkeypatch the ruby core classes (Object and BaseObject)
RSpec 3 has a new syntax which does not rely on monkeypatching:
before do
expect_any_instance_of(SomeModule::Salesforce).to receive(:materialize)
end
Ok I've just found that I was looking in wrong sources, it doesn't come from RSpec but from Mocha Mock (expects and any_instance) http://gofreerange.com/mocha/docs/Mocha/Mock.html#expects-instance_method
Thanks #tomasz-pajor #https://stackoverflow.com/users/2928259/tomasz-pajor
I've been looking for some tutorials on creating ruby gems, but all seem to be overly complicated. Essentially, all I want is to make a gem that (trivial example alert) allows the user to place a method add_one(x) in their code, once the gem is installed.
A lot of tutorials explain how you can call the gem's methods with Classname.method(), but that's really not what I want. RyanB has a good example here, but again I can't get it to work - mainly because of the 3 lines of code at the bottom of uniquify.rb that read.
class ActiveRecord::Base
include Uniquify
end
In my case, my main module is called AddOne, so how would I go about doing this? Again, sorry for the trivial example, I'm just looking to get started so that my gems will allow the user to call plain ol' methods, without specifying Modules or Classes. In Ryan's example, he's able to simple call uniquify() in the code.
In the example given, he can call uniquify as a method because he is calling it inside a class which includes ActiveRecord::Base. (He calls uniquify inside the class Product < ActiveRecord::Base...end block) There isn't any real magic here.
To my understanding, what you desire is easily achievable, but isn't a good idea, 'best practice' considered. You can define anything you want in your gem. For instance, I could package a file called say_hello.rb inside a gem called salutations.
say_hello.rb
def say_hello
puts "Hello everybody"
end
By requiring the packaged gem salutations I would gain access to anything defined therein. However, it might lead to unexpected consequences. Do what you need to do, but just understand that it might not be the best idea. Hence, you build things into classes or modules to contain them, and to prevent conflicts with other code. Good luck.