I am using RubyDNS.
When I use match block and otherwise, I want to skip some addresses in match so they would be caught by otherwise block.
But it doesn't go to otherwise block.
RubyDNS.run_server(listen: INTERFACES, asynchronous: false) do
upstream = RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])
match(/^([\d\.]+)\.in-addr\.arpa$/, IN::PTR) do |transaction, match_data|
domain = nil # just for test
if domain
transaction.respond!(Name.create(domain))
else
# Pass the request to the otherwise handler
# !!! this doesn't work
false
end
end
otherwise do |transaction|
transaction.passthrough!(upstream)
end
end
When I return false from match block - it doesn't go to otherwise block.
How to fix this?
I found how to continue to otherwise block from match block: use 'next!'
match(/^([\d\.]+)\.in-addr\.arpa$/, IN::PTR) do |transaction, match_data|
domain = nil # just for test
if domain
transaction.respond!(Name.create(domain))
else
# Pass the request to the otherwise handler
next!
end
end
otherwise do |transaction|
transaction.passthrough!(upstream)
end
Related
I have a very simple example where sinatra simply returns no output.
The program enters the if clause but the block is not finished and therefore nothing is sent to rack, nothing goes to the browser... not a single character.
require 'sinatra'
get '/' do
var='confirmed'
if var == 'confirmed'
'Confirmed'
end
if var == 'declined'
'Declined'
end
end
The question is now: Is adding a "return" or "next" the way this is usually done? With it, its running... But I never found an example in the net that had to use a next statement...
So, is the "if logic" usually somewhere else and there is only a single erb :xyz at the end of a route?
I am confused...
You have the answer mostly. You always need to send something to rack to get a response.
You probably have a view to show the status on then you add at the end something like this (You can have multiple erb blocks just add for each route a erb call):
get '/' do
var='confirmed'
if var == 'confirmed'
st = 'Confirmed'
end
if var == 'declined'
st = 'Declined'
end
erb :myViewName, :locals => {:status => st}
end
Or just use return like this, if your response is just a string. Be aware that everything after this return isn't executed:
if var == 'confirmed'
return 'Confirmed'
end
It's nothing to do with the way Sinatra works, really. It's more of a Ruby matter. According to Sinatra readme:
The return value of a route block determines at least the response body passed on to the HTTP client, or at least the next middleware in the Rack stack. Most commonly, this is a string, as in the above examples. But other values are also accepted.
The problem in your code is that your last if is a statement itself. If your var variable isn't "declined", then the if block evaluates to nil, and as it is the last value in your route block, this is what gets returned by Sinatra.
When you use explicit return, you don't get to the second if and don't have this issue, which is why it works with explicit return.
You would not need an explicit return with a if/elsif block like this:
# This is one single statement that would return either confirmed or declined
# Request will always return a non-nil value
get '/' do
...
if var == 'confirmed'
'Confirmed'
elsif var == 'declined'
'Declined'
end
end
Or a case/when block:
# This is one single statement that would return either confirmed or declined
# Request will always return a non-nil value
get '/' do
...
case var
when 'confirmed' then 'Confirmed'
when 'declined' then 'Declined'
end
end
The task is to check if a contact page exists and navigate to it. For the websites not in english, the method looks for an english page and then restarts to check for a contact page.
My conditional works fine, but I figured there must be a better way to do this:
# First, I set the #url variable during Booleans.
# Checks are either to see if a link exists or if a page exists,
# (aka no 404 error).
#
# Here are two examples:
# Boolean, returns true if contact link is present.
def contact_link?
#url = link_with_href('contact')
!#url.nil?
end
# True if contact page '../contact' does NOT get a 404 error.
def contact_page?
#url = page.uri.merge('../contact').to_s
begin
true if Mechanize.new.get(#url)
rescue Mechanize::ResponseCodeError
false
end
end
# #
# Now go to the correct page, based off of checks.
#
def go_to_contact_page
1.times do
case # No redo necessary.
when contact_link? # True if hyperlink exists
get(#url)
when contact_page? # False if 404 error
get(#url)
else # Redo is now necessary.
if english_link? # True if hyperlink exists
get(#url)
redo
elsif en_page? # False if 404 error
get(#url)
redo
elsif english_page? # False if 404 error
redo
end
end
end
end
There are a couple things to draw your attention to:
Is 1.times do the best way to do a single redo? Would begin be better?
Understanding that I set the #url variable in each of these checks, there seems to be redundancy in get(#url) in the conditional branch. Is there a more succinct way?
I am writing redo three times which also seems redundant. Is there a way to call it once and still set the #url variable?
Thanks for the help!
Something like this is more readable and dry
def english_contact_page
..
rescue
nil
end
def contact_page
..
rescue
nil
end
def get_page
#url = link_with_href('contact')
return nil if #url.nil?
contact_page || english_contact_page # left side is evaluated first
rescue
nil
end
I have been trying to use Minitest to test my code (full repo) but am having trouble with one method which downloads a SHA1 hash from a .txt file on a website and returns the value.
Method:
def download_remote_sha1
#log.info('Downloading Elasticsearch SHA1.')
#remote_sha1 = ''
Kernel.open(#verify_url) do |file|
#remote_sha1 = file.read
end
#remote_sha1 = #remote_sha1.split(/\s\s/)[0]
#remote_sha1
end
You can see that I log what is occurring to the command line, create an object to hold my SHA1 value, open the url (e.g. https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.4.2.deb.sha1.txt)
I then split the string so that I only have the SHA1 value.
The problem is that during a test, I want to stub the Kernel.open which uses OpenURI to open the URL. I would like to ensure that I'm not actually reaching out to download any file, but rather I'm just passing the block my own mock IO object testing just that it correctly splits stuff.
I attempted it like the block below but when #remote_sha1 = file.read occurs the file item is nil.
#mock_file = Minitest::Mock.new
#mock_file.expect(:read, 'd377e39343e5cc277104beee349e1578dc50f7f8 elasticsearch-1.4.2.deb')
Kernel.stub :open, #mock_file do
#downloader = ElasticsearchUpdate::Downloader.new(hash, true)
#downloader.download_remote_sha1.must_equal 'd377e39343e5cc277104beee349e1578dc50f7f8'
end
I was working on this question too, but matt figured it out first. To add to what matt posted:
When you write:
Kernel.stub(:open, #mock_file) do
#block code
end
...that means when Kernel.open() is called--in any code, anywhere before the stub() block ends--the return value of Kernel.open() will be #mock_file. However, you never use the return value of Kernel.open() in your code:
Kernel.open(#verify_url) do |f|
#remote_sha1 = f.read
end
If you wanted to use the return value of Kernel.open(), you would have to write:
return_val = Kernel.open(#verify_url) do |f|
#remote_sha1 = f.read
end
#do something with return_val
Therefore, the return value of Kernel.open() is irrelevant in your code--which means the second argument of stub() is irrelevant.
A careful examination of the source code for stub() reveals that stub() takes a third argument--an argument which will be passed to a block specified after the stubbed method call. You, in fact, have specified a block after your stubbed Kernel.open() method call:
stubbed method call -+ +- start of block
| | |
V V V
Kernel.open(#verify_url) do |f|
#remote_sha1 = f.read
end
^
|
end of block
So, in order to pass #mockfile to the block you need to specify it as the third argument to Kernel.stub():
Kernel.stub(:open, 'irrelevant', #mock_file) do
end
Here is a full example for future searchers:
require 'minitest/autorun'
class Dog
def initialize
#verify_url = 'http://www.google.com'
end
def download_remote_sha1
#remote_sha1 = ''
Kernel.open(#verify_url) do |f|
#remote_sha1 = f.read
end
#puts #remote_sha1[0..300]
#remote_sha1 = #remote_sha1.split(" ")[0] #Using a single space for the split() pattern will split on contiguous whitespace.
end
end
#Dog.new.download_remote_sha1
describe 'downloaded file' do
it 'should be an sha1 code' do
#mock_file = Minitest::Mock.new
#mock_file.expect(:read, 'd377e39343e5cc277104beee349e1578dc50f7f8 elasticsearch-1.4.2.deb')
Kernel.stub(:open, 'irrelevant', #mock_file) do
#downloader = Dog.new
#downloader.download_remote_sha1.must_equal 'd377e39343e5cc277104beee349e1578dc50f7f8'
end
end
end
xxx
The second argument to stub is what you want the return value to be for the duration of your test, but the way Kernel.open is used here requires the value it yields to the block to be changed instead.
You can achieve this by providing a third argument. Try changing the call to Kernel.stub to
Kernel.stub :open, true, #mock_file do
#...
Note the extra argument true, so that #mock_file is now the third argument and will be yielded to the block. The actual value of the second argument doesn’t really matter in this case, you might want to use #mock_file there too to more closely correspond to how open behaves.
Im having difficulty using .match to only allow and block selective tweets and display only those from 'does_match?'
def does_match?
allow = "/orange|grape\sfruit|apple/"
block = "/#fruits|coconut/"
allowfruits = "/berry|mango/"
#tweet.match(allow).nil?
#tweet.match(block)
#tweet.match(allowfruits) if #user =~ /\A(twitteruser|anotheraccount)\Z/
#tweet.match(/#[A-Za-z0-9_:-]+/)
return #tweet
end
def show
return #tweet
end
firstly, You are defining Your regexps as a strings
do this instead
allow = /orange|grape\sfruit|apple/
secondly, You're doing some matches bot doing nothing with its return values
do this
if #tweet.match(allow)
# rest of logic
# checking blocked and allowed for user
#tweet # or true
else
nil # or false
end
is there a way to stop execution and return a different value in a before do block in sinatra ?
before do
# code is here
# I would like to 'return "Message"'
# I would like "/home" to not get called.
end
// rest of the code
get '/home' do
end
before do
halt 401, {'Content-Type' => 'text/plain'}, 'Message!'
end
You can specify only status if you want, here's example with status, headers and body
On http://www.sinatrarb.com/intro Filters section
Before filters are evaluated before
each request within the context of the
request and can modify the request and
response. Instance variables set in
filters are accessible by routes and
templates:
before do
#note = 'Hi!'
request.path_info = '/foo/bar/baz'
end
get '/foo/*' do
#note #=> 'Hi!'
params[:splat] #=> 'bar/baz'
end