Ruby Koans about_methods line 123 object loop - ruby

Each time I add in the correct code, it gives me the same error due to AboutMethods:0x00000101841a28 number changing each time. It's like its stuck and I don't know how to get out this loop. It worked once, then I went on to the next step, but then it triggered an error after that.
I must not be inputting the correct line of code given from the console?
def test_calling_private_methods_with_an_explicit_receiver
exception = assert_raise(NoMethodError) do
self.my_private_method
end
assert_match "private method `my_private_method' called for #<AboutMethods:0x000001008debf8>", exception.message
end
The AboutMethods:0x000001008debf8 changes each time, not sure how to approach this problem?

AboutMethods:0x... is the output of the inspect method, which usually (and in this case) includes the class name (AboutMethods) and the object id (0x...). The object id is related to the objects location in memory, so it will change every time.
In my experience, there is very little value to checking the string from an exception (it's brittle). However, if you feel the need, use a regex:
assert_match /private method `my_private_method' called for \#\<AboutMethods:.*/

Related

What to put in rspec's expect for a globally available object?

I am writing a custom matcher for my logging output, mostly so that I can customize the error output to be more readable and helpful.
The thing being examined for the test is the array returned by LoggingSpecHelper.log_events, a module class method (i.e. not a module instance method). Therefore, it is available without the need for it to be passed as a parameter.
LoggingSpecHelper.log_events is kind of long to specify in each expectation, and anyway I'd prefer to hide that implementation detail from the caller, in case that implementation changes. That leads to my using expect(:logging), where :logging is a dummy value which has no meaning and is not examined. This, however, is awkward and confusing, leaving the reader scratching their head thinking "he's examining a symbol?"
Here is an example of how it is currently called; in this case I'm looking to see if a fatal error occurs in the log that contains 'something is misconfigured' (not a real production message):
expect(:logging).to have_log_output_match(:fatal, 'something is misconfigured')
The long form of this, and what is happening in the matcher, is below, but if I do this instead of calling the matcher, I don't get to see what is in the log if an error occurs (the matcher includes log content in the failure message):
expect(LoggingSpecHelper.log_events.count do |event|
event.level == :fatal && /something is misconfigured/.match?(event.message)
end).to be == 1
How would you suggest I handle this? I don't think shared examples are what I want here because this log expectation might not be the only expectation in the example.
As an aside, I should probably rename the matcher so that it is clear that I am testing for 1 and not >=1 occurrences.

Ruby Sinatra Upload Form params Disturbed

Upon submitting a form in Sinatra, I'm coming up with the following error:
App 40327 output: 2018-06-28 02:59:17 - NoMethodError - undefined method `[]' for nil:NilClass:
App 40327 output: /Library/WebServer/Documents/blammo/routes/publish.rb:87:in `block in <class:MyApp>'
The form is a file upload form, and a single text field. Simple. The file goes through, as does the text field. They are both captured just fine.
I submit the params to a method, which is ultimately responsible for generating the error on the following line down the page:
fname = params[:s_single_file_upload][:filename]
The method in question returns fine with a boolean. I've rewritten it a couple of ways and flushed out anything that might trip something I'm
unfamiliar with.
So the params is messed up if this method mentioned above is being called. So fname can't be assigned. I expect the params to be intact
at this point in the code. Is there any destruction if the params are perused before this point? In another language, I've seen params destroyed
in one way or another for some reason, but I'm not sure about Ruby.
I'm not finding any nil:NilClass, but that's exactly what it's reporting. Here's the trigger of this method:
result = Alpha::rf_alpha_sniff(params)
And the module::method:
module Alpha
def self.rf_alpha_sniff(incoming)
qualifiers = %w(alpha bravo charlie delta echo foxtrot)
incoming.delete('captures')
incoming.delete('splat') # take out Mustermann's 'captures' and 'splat'
incoming.delete('s_single_file_upload') # non-perusal 'single_file_upload'
incoming.values.each do |item|
item = item.gsub(" ","_")
Dev::hq_log("item: #{ qualifiers.include?(item.downcase) }")
return true if qualifiers.include?(item.downcase)
end
return false
end
end
So the page progresses fine without this method. When the method is induced any way, the params seem to get screwed up, so the file is pretty much
gone.
How is this method interfering with the params so that it's unavailable later on down the script? I'm expecting it to be fully available everywhere.
Turns out, using incoming.delete was deleting items from the params hash, as it was a reference to the original, instead of using a copy.
So, I have to copy the params by using params.dup (duplicate) so they are not the same object.
Having a view of the params hash post-testing-method, showed me that objects were indeed deleted. Another one solved.

Rspec check if a method has been called without calling the method

I am pretty new with RSpec an althought I have been reading a lot about how to check if a method has been called I cannot find a proper solution for the case I need. Sorry if this is a duplicate but couldn't find anything :S
I have an object which implements this function
def link
paths.each do |old,new|
FileUtils.ln_s old, new
end
end
Several links are done based on paths (which is a hash pairing old and new files). My test for this looks like this:
context "linking files to new ones" do
it "links a sample to the propper file" do
#comb.link
expect(FileUtils).to have_received(:ln_s).with("/example/path/files/old.root",
"example/path/nornmfiles/new.root")
end
end
Since I want to test that at least on of them has been called have to use the have_received method since the receive ones will fail as soon as the ln_s method gets called with different arguments. The issue is that the test fails because this is a test and I an mot going to actually create the links because the files don't exists so it fails raising an exception because the files don't exists.
How can I test this without actually having to call the method?
This call also fail as soon as a different call is made
it "links a sample with a region subpath to the propper file" do
expect(FileUtils).to receive(:ln_s).with("/example/path/files/pathsuff/old.root",
"/example/path/normfiles/pathsuff/new.root").at_least(:once)
#comb.link
end
It gives this error:
RSpec::Mocks::MockExpectationError: FileUtils received :ln_s with unexpected
arguments
expected: ("/example/path/files/pathsuff/old.root",
"/example/path/normfiles/pathsuff/new.root")
got: ("/example/path/files/old.root",
"/example/path/normfiles/new.root")
which is on of the other calls with different methods that can happen that can be called
context "linking files to new ones" do
it "links a sample to the propper file" do
allow(FileUtils).to receive(:ln_s)
#comb.link
expect(FileUtils).to have_received(:ln_s).with(
"/example/path/files/old.root",
"example/path/nornmfiles/new.root",
).at_least(:once)
end
end
If you don't care about actual arguments (but rather simple number of calls)
expect(FileUtils).to receive(:ln_s).with(anything, anything).exactly(paths.length).times
#comb.link
If you do care about arguments
expect(FileUtils).to receive(:ln_s).with('foo', 'bar').ordered
expect(FileUtils).to receive(:ln_s).with('foo2', 'bar2').ordered
expect(FileUtils).to receive(:ln_s).with('foo3', 'bar3').ordered
#comb.link

Rails logger formatting - insert method name calling logger method

I want to insert name of the method calling the logger methods into my log files. Not the whole stack trace, but the class, method and/or line number would be great.
In any method, one can use caller to get an array of strings, each of which contains the file, line number and method name. I've come up with a pretty awful kludge using regexes and Enumerable#find to try to return the first non-logger stack frame. I guess it works, but if the locations of the logging Ruby files change in a different version or Rails, or I name my files something to do with logs, it will break. Same with if I take a given index from the top of the stack (I did this at first, then refactored one thing and naturally it gave me the wrong frame).
Note that I'm not looking to just log the controller or action, as those can be retrieved easily. Mostly this is for stuff in the lib/ directory.
Isn't there an easy way to do this? I don't want to have to pass in __method__ every time I make a logging statement.
I've looked all over at different solutions for capturing the exact place (file, line number, method name) where I invoke any given logger instance method from within my rails app. To do this, you need to override Logger's format_message method, and a good place to do this is in your rails project's config/environment.rb file.
This is what I've come up with, which is good enough for me ;o)
class Logger
def format_message(severity, timestamp, progname, msg)
line = ''
Kernel.caller.each{|entry|
if (entry.include? Rails.root.to_s)
line = " #{entry.gsub(Rails.root.to_s,'').gsub(/\/(.+)\:in `(.+)'/, "\\1 -> \\2")}"
break
end
}
"[#{timestamp.strftime("%Y%m%d.%H:%M:%S")}] #{severity}#{line}: #{msg}\n"
end
end
Kernel.caller holds an enumerable array of the entire backtrace. If you look at it in its entirety, you'll see most calls are internal inside of a gem somewhere well outside your project. I've found that by looping through the Kernel.caller until I find the first place that includes my Rails.root, I can get the line with the information I want to parse.
Example:
If I call Rails.logger.debug("Streamer class started!") from the start method of my Streamer class, the raw entry would look like this:
/Users/chikoon/www/my_rails_app/lib/streamer.rb:7:in `start'
so by the time it makes it through my formatter, I've got the timestamp, severity mode, the file path, line number, method name, and message:
[20140919.19:23:44] DEBUG lib/streamer.rb:7 -> start: Streamer class started!
I hope that helps get your wheels turning.
How about setting up log_tags to call the __method__?
Blog::Application.configure do
config.log_tags = [lambda { |req| __method__ }]
end

Rails: ParameterFilter::compiled_filter tries to dup symbol

I'm running rails3 with rails exception-notifier gem. When an exception occurs, and an email should be sent, I'm getting an exception from the ParameterFilter class. I've found the problem in the rails source, and am not sure the best way to proceed.
The problem occurs in ActionDispatch::Http::ParameterFilter. In the compiled_filter method, an error occurs on line 38: key = key.dup when key is a symbol, because symbols are not duplicable. Here is the source:
def compiled_filter
...
elsif blocks.present?
key = key.dup
value = value.dup if value.duplicable?
blocks.each { |b| b.call(key, value) }
end
I see that they only call dup on value when it is duplicable. If I patch the source to only call dup on key when key is duplicable, then my problem goes away. I'm assuming there is a reason why the author put that condition on value and not key, so I'm curious if someone out there has a better understanding of this code.
This error only occurs when you add a block to your filter params in application.rb. So, maybe there is a workaround for my original issue that does not require using a block here. If you're interested see my coworker's question Rails: Filter sensitive data in JSON parameter from logs
The key for which this is a problem is :action. This comes from rails and I don't know if there is any way to force it to be a string instead.
I filed a rails bug https://rails.lighthouseapp.com/projects/8994/tickets/6557-symbol-duplication-error-in-parameterfilter-compiled_filter and I have a patch ready that adds if key.duplicable? to the key.dup line, I'm looking for input on whether or not that is the right solution.
This looks like a bug in Rails. Either the key should be a string rather than a symbol, or the dup should be protected by duplicable?.
You should file a bug at https://rails.lighthouseapp.com/, including a minimal test case if possible.

Resources