Access Ruby Instance Variable from Included Module - ruby

I have a Sinatra API file that has following code-
require 'json'
require_relative 'api_logger'
include ApiLogger
get /myapi/:id
request_params = request.env
write_log('log message')
end
Then I have a module containing the methods 'write_log'-
module ApiLogger
def write_log(message)
file.write(request['user']+message)
end
But request['user'] is coming out blank.
So the question is how to access the request variable from Sinatra API file in ApiLogger module? Also, I'm creating service class objects from API class and pass them request object at initialization. Can the module 'ApiLogger' access that 'request' instance variable from service class if the service classes just include 'ApiLogger'?

You could pass it as an additional argument.
Something like:
require 'json'
require_relative '../../lib/helpers/api_logger'
include ApiLogger
get /myapi/:id
request_params = request.env
write_json_log('log message', request)
end
and
def write_json_log(message, request)
file.write(request['auth_subject']+message)
end

I did not want to pass request object to each method. So I made 'request_params' a global variable in all classes that need to log and added this line in 'ApiLogger' to fetch the value of request object-
request = instance_variable_get '#request_params'

You were almost there, all you needed was include your module in the helpers in order to have a direct access to the request object. Here's a slightly modified version of your code that runs as a standalone program:
require 'sinatra'
module ApiLogger
def write_log(message)
$stdout.write(request.env['sinatra.route'] + message)
end
end
helpers do
include ApiLogger
end
get '/test' do
write_log('log message')
'ok'
end

Related

Parsed_response in Ruby from HTTP

How can i get parsed_response from here?
require 'HTTParty'
require 'httparty/request'
require 'httparty/response/headers'
class CRUD
include HTTParty
def retrieve
##response = CRUD.get('http://dummy.restapiexample.com/api/v1/employee/id')
end
end
{"id":"719","employee_name":"test","employee_salary":"123","employee_age":"23","profile_image":""}
puts #manter_user.retrieve.parsed_response['employee_name'] -- dont work
puts CRUD.class_variable_get(:##response).parsed_response['employee_name'] -- dont work
It's an instance method, it means that you need to create an instance. And you don't need global variable. And it is bad idea to name class with all uppercase letters - this style is used for constants. Classes and modules use MixedCase and have no underscores, each word starts with an uppercase letter.
class Crud
include HTTParty
def retrieve
self.class.get('http://dummy.restapiexample.com/api/v1/employee/id')
end
end
> Crud.new.retrieve.parsed_response
Since you are getting the JSON response, you can parsed it back as
require 'json'
foo = JSON['{"id":"719","employee_name":"test","employee_salary":"123","employee_age":"23","profile_image":""}']
puts foo['employee_name'] # => test

Handling a method from outside of a mixin module in ruby and rspec

I have a class that looks like this:
module ReusableBitlyLinks
def shorten_url url, *args
ShortenedUrl.shorten_url_with_bitly( url, email.user )
end
end
I have a test that looks like this:
require File.expand_path("../../../../app/decorators/mixins/reusable_bitly_links", __FILE__)
include ReusableBitlyLinks
describe ReusableBitlyLinks do
describe "shorten_url" do
it "works" do
ReusableBitlyLinks.shorten_url('asdf').should == 'asdf'
end
end
end
When I run the test I get an error that says:
uninitialized constant ReusableBitlyLinks::ShortenedUrl
How do I mock stub ReusableBitlyLinks::ShortenedUrl?
Is ShortenedUrl defined inside ReusableBitlyLinks module? If not - try to access it with ::ShortenedUrl.shorten_url_with_bitly.
Not sure what stubbing has to do with it...
In your mixin module, you need to tell it that ShortenedUrl is from outside the module by prepending :::
module ReusableBitlyLinks
def shorten_url(url, *args)
::ShortenedUrl.shorten_url_with_bitly(url, email.user)
end
end
You may also need to do a require inside the mixin file to load whatever file it is that defines ShortenedUrl.
Further, in your test file, the line:
require File.expand_path("../../../../app/decorators/mixins/reusable_bitly_links", __FILE__)
could be simplified to:
require_relative '../../../../app/decorators/mixins/reusable_bitly_links'

How to create and call parameterised page-object classes

I am using page-factory visit, on methods to call page-object classes from spec file in ruby. I would like know how to parameterise page-object classes, passing parameters from spec file using page factory methods.
I want to log all steps information in page-object class. To do this, I created a log in spec file using the logger gem. I need to pass the log object as input parameter to page classes to capture data. Here is the code I am using to do this.
spec file that calling page class:
require './lib/pages/Test_page'
file="logs/uniusecase_#{#ncs_server['build_no']}_#{#ncs_server['test_type']}_#{time}.log"
$log=Logger.new(file)
describe 'testcase-1',:sanity do
visit Testpage, using_params: {logger: $log} do |page|
end
end
page-object class:
class Testpage
include PageObject
log = "<%=params[:logger]%>"
def goto
log ("test msg-1")
end
def testmethod()
log("test msg -2")
end
end
I am getting "NameError: undefined local variable or method `log' error message while execution. Could somebody help me in doing this?
The :using_params are stored in the class' #merged_params variable. You can get this variable by doing:
self.class.instance_variable_get(:#merged_params)
So your method would look something like:
def goto
logger = self.class.instance_variable_get(:#merged_params)[:logger]
logger("test msg-1")
end
However, if you are defining the logger in a global variable, it will already be available to the page object class (ie you do not need to pass it along). In other words, you could simply do:
def goto
$log ("test msg-1")
end

Sinatra: how to use helpers in dynamically generated routes?

I create a route for each product from database with following code:
Products.all.each do |product|
get "/#{product.title.latinize}"
end
end
class String
def latinize
self
end
end #or with helpers
which raises NoMethodError: undefined method `latinize' for "hello":String.
How to use helpers (or class's extensions as seen here) from dynamically generated routes in Sinatra?
It's probably because you are defining the latinize method after you are generating the routes. Move to above the Product.all section.

Use api key in HTTParty

I am trying to access a service which uses the url format. www.example.com/api/API_KEY/action
The below code is a small example of what I'm trying to achieve.
require 'httparty'
class MyAPI
include HTTParty
debug_output $stdout
base_uri "example.com/api/#{#api_key}"
def initialize(api_key)
#api_key = api_key
end
def statistics
return self.class.get("/statistics")
end
end
The server request:
MyAPI.new('apikey').statistics
comes out as
GET /api//statistics
I knew it was optimistic but I put the api_key variable in the base_uri. How do I make it so that the url uses the dynamic api_key?
You are missing a reader method for #api_key.
Add the following to your class to allow the setting of #api_key after initialization.
attr_accessor :api_key
Or add to allow it to be read, but not set later.
attr_reader :api_key

Resources