Coffeescript error "undefined is not a function" in hubot - coffeescript

I'm making call to my django app that returns a JSON object and I'm using the following code to do so:
robot.hear /lunch for today/i, (res) ->
robot.http("http://my_ip_address/show")
.header('Accept', 'application/json')
.get() (err, res, body) ->
data = JSON.parse body
res.send data.food
but it returns ERROR TypeError: undefined is not a function in the console. What's wrong with this?

is should look like this:
module.exports= (robot) ->
robot.hear /lunch for today/i, (msg) ->
robot.http("http://my_ip_address/show")
.header('Accept', 'application/json')
.get() (err, res, body) ->
console.log res.statusCode
data = JSON.parse body
msg.send data.food
I believe the reason it is failing is because you are using res in the place of msg and then res again in the context of the function .get()

I'm guessing the error is on this line:
.get() (err, res, body) ->
Instead of passing the callback as an argument to get, you're calling get with no arguments and then trying to call the result (which is undefined) as though it were a function. My CoffeeScript is rusty, but I think you want this instead:
.get (err, res, body) ->

It might be incompatible version of installed hubot and documentation but I found out the res from an http method has no send, but the one from the /hear command does.
robot.hear /lunch for today/i, (res) ->
robot.http("http://my_ip_address/show")
.header('Accept', 'application/json')
.get() (err, msg, body) ->
data = JSON.parse body
res.send data.food
This should work, but either the official documentation is wrong, either the default installation of hubot is outdated.

Related

Using .catch with async/await

I am wondering if I can still use .catch() within an async function to catch the error instead of using a try-catch block.
The following code is from my project using MongoDB and Express:
router.get('/communities', EnsureAuthenticated, async (req, res) =>{
//Look up the user in the db + populate the community field
const userInfo = await User_DB
.findOne({ _id:req.user._id, })
.populate('communities')
.lean()
.catch(err => {
console.log(err)
res.status(500)
.json({
msg: 'DB: Error Fetching User Info',
});
// rest of the functions that take userInfo as the input
});
When using try-catch all variables will be limited to within the scope of that try-catch block.
If I need to use the userInfo as the input for other functions down the line I'll have to put everything within that try-catch block which doesn't look clean and can be confusing. Because you don't know which function does the error belongs to if there is any.
Is my understanding correct?
I apologize for the formatting. I'm doing this on my phone.
You can also make a central error handler, you can find an example here

Coffeescript wait for multiple api calls to be over

i am writing a coffeescript, where i am calling around 1000 http URL 's, parsing each and every data from each call and creating an array of result objects. Finally i need to access the array of objects and sort them.
Whats happening is, the code is not waiting for each and every call to be over and instead goes to end of the code where i am sorting the result array. Since the api calls are not over, the resulting array is null and hence getting an exception. I am pasting my code below. Please help me here
topChannels = []
calcMsgCount = (value) ->
channelhistoryURL = 'https://some-url'
msg.http(channelhistoryURL)
.header('Accept', 'application/json')
.get() (err, res, body) ->
if res.statusCode is 200
try
data = JSON.parse body
Channel =
id: data.id
name: data.name
messagecount: data.messages.length
topChannels.push(Channel)
value++
if (value < response.channels.length)
setTimeout calcMsgCount(value),1000
catch err
msg.send "JSON parsing error"
msg.send value
msg.send err
else
msg.send "error while retrieving channel history"
index=0;
calcMsgCount(index);
# Sorting topChannels array based on total number of messages
sortByMsgCount = (array, key) ->
array.sort((a,b) -> b[key] - a[key])
sortByMsgCount(topChannels, 'messagecount')

Understanding coffescript functions scope and return object kind - while trying to get JSON

I would like to have some function getTagsDict() visible to broder scope, which will be responsible for some GET request to the server and returning dictionary, which can be then easily accesed in loop like:
for k,v of getTagsDict()
For now below code returns some js crap (or at least for js-newbie): http://i.imgur.com/A3YtobD.png
getTagsDict = () ->
$.get '/notifications/ajax_avalaible_search_tags/', (data) ->
data
$ ->
$('#ajax_search_input').on 'keyup', (e) ->
for k,v of getTagsDict()
console.log "#{k} and #{v}"
But when doing GET just inside the calling method everything works well:
$ ->
$('#ajax_search_input').on 'keyup', (e) ->
$.get '/notifications/ajax_avalaible_search_tags/', (data) ->
for k,v of data
console.log "#{k} and #{v}"
QUESTION: How should I use coffee's functions to be globaly and to be utilized as described?
The clue was to build getTagsDict as function with asynchronus ajax call. It can look for example like this:
getTagsDict = ->
strReturn = ""
jQuery.ajax
async: false
url: "/notifications/ajax_avalaible_search_tags/"
success: (data) ->
strReturn = data
strReturn

return value from a jquery get callback function

It would be very useful to me if you could help me fix this function:
textParseQuery = (txtSnippet) ->
queryUrl = "http://localhost:8083/txtParse/#{txtSnippet}"
console.log queryUrl
callback = (response) =>
parsed = $.parseJSON response
companies = parsed.map (obj) -> new Company(obj.name, obj.addr)
companies
res = $.get queryUrl, {}, callback
console.log res
I would like to fetch the results from the callback so that the textParseQuery function could return a value.
The point of a callback is it's asynchronous, your response comes in the callback, so you need to handle the rest of the execution from the callback (e.g., the console.log res is going to execute before your callback is called, since it's part of the same synchronous execution of your ajax call).
textParseQuery = (txtSnippet) ->
queryUrl = "http://localhost:8083/txtParse/#{txtSnippet}"
callback = (response) ->
parsed = $.parseJSON response
companies = parsed.map (obj) -> new Company(obj.name, obj.addr)
# proceed from here
console.log companies
$.get queryUrl, {}, callback
Additional note: the fat arrow is unnecessary here, it's used to rebind what this refers to, but you aren't referencing this at all in your callback. If you're learning coffee, most editors will have plugin/modules to quickly compile coffee to JS, so use that to see what a given coffee syntax compiles to in JS (e.g., take a look at the diff between using -> and => when you compile your coffee)
I have discovered IcedCoffeeScript helps streamline the asynchronous control flow with await and defer. This is what I have tried to achieve. The code structure is how I pictured it
# Search for 'keyword' on twitter, then callback 'cb'
# with the results found.
search = (keyword, cb) ->
host = "http://search.twitter.com/"
url = "#{host}/search.json?q=#{keyword}&callback=?"
await $.getJSON url, defer json
cb json.results

Method Callback Returning Undefined [CoffeeScript]

I am calling a simple google api using an HTTP method on the server. It appears I am getting a json object back, yet the callback on the client seems to return an undefined object.
My guess is somehow the result isn't making it to the callback in time. A bit confused.
Full code here:
if Meteor.isClient
Meteor.startup () ->
console.log "Client Started."
Meteor.call("getGeocode", 94582, (error, result) ->
console.log "GeoCode returned to client, #{result}."
Session.set("latitude", result))
Template.results.latitude = () ->
Session.get("latitude")
Template.results.longitude = () ->
"longitude"
if Meteor.isServer
Meteor.startup () ->
console.log "Server Started"
Meteor.methods
"getGeocode": (zipCode) ->
result = HTTP.call("GET", "http://maps.googleapis.com/maps/api/geocode/json?address=#{zipCode}&sensor=false")
console.log "Geocode called, returning #{result}."
Your getGeocode method is returning undefined because CoffeeScript will automatically return the result last statement in the function, which in this case is a console.log.
I don't think result is really want you want though. I recommend including util at the start of your isServer section like so:
if Meteor.isServer
util = Npm.require 'util'
Now you can call console.log util.inspect result, {depth: null} to see what it's made of. I think what you may actually want to return is result.data.results[0]. Your code could look something like:
if Meteor.isClient
Meteor.startup () ->
console.log "Client Started."
Meteor.call("getGeocode", 94582, (error, result) ->
Session.set("latitude", result.geometry.location.lat))
Template.results.latitude = () ->
Session.get("latitude")
Template.results.longitude = () ->
"longitude"
if Meteor.isServer
util = Npm.require 'util'
Meteor.startup () ->
console.log "Server Started"
Meteor.methods
"getGeocode": (zipCode) ->
result = HTTP.call("GET", "http://maps.googleapis.com/maps/api/geocode/json?address=#{zipCode}&sensor=false")
geoData = result.data.results[0]
console.log util.inspect geoData, {depth: null}
geoData