Hubot Hear Variable - coffeescript

I was hoping to find away to get hubot to here a variable.
Ex
name = "Peter"
module.exports = (robot) ->
robot.hear /hello name/i, (msg) ->
msg.send "Peter?! No I am Hubot."
I have already tried "#{}" syntax like below, but got nowhere with it.
name = "Peter"
module.exports = (robot) ->
robot.hear /hello #{name}/i, (msg) ->
msg.send "Peter?! No I am Hubot."
Any help would be greatly appreciated.
Regards,
Austin

Since your regex is not a constant, you should use new Regex():
Using the constructor function provides runtime compilation of the regular expression. Use the constructor function when you know the regular expression pattern will be changing, or you don't know the pattern and are getting it from another source, such as user input.
Code
name = "Peter"
regx = new Regex("hello #{ name }", 'i')
module.exports = (robot) ->
robot.hear regx, (msg) ->
msg.send "Peter?! No I am Hubot."
Edit
With name as a parameter
module.exports = (robot, name) ->
regx = new Regex("hello #{ name }", 'i')
robot.hear regx, (msg) ->
msg.send "#{ name }?! No I am Hubot."

In case its useful, a hubot example using javascript rather than coffeescript that also takes the option chosen and places it in another variable:
const options = 'now|later|never';
const regexOptions = new RegExp(`starting (${options})`, 'i');
robot.respond(regexOptions, (msg) => {
// this will respond to:
// hubot starting now
// but not to:
// hubot starting notAnOption
const optionChosen = msg.match[1];
msg.send(`option chosen: ${optionChosen}`);
});
I use this technique when I have dynamic lists that I can add or remove names into, that I then want to use within responses - it does require a quick reload of hubot when adding a name to a list used in a command of course.

Related

error: unexpected if for unknown reasons

I don't have a clue why this happens, but here is code of the file:
express = require "express"
fs = require "fs"
router = express.Router()
module.exports = (config) ->
fileRe = /^([a-zA-Z0-9-_]+)(\.(png|jpg|jpeg))?$/i
router.get '/:file', (req, res) ->
file = req.params.file
if !file or !fileRe.test file
return res.error(404).send "404 Not Found"
fileInfo = fileRe.exec file
if !fileInfo[3]
# .png is default if extension is ommited
# abc => abc.png, but abc.jpg will stay
file += ".png"
if fs.access config.destination + file, fs.F_OK, (err) ->
if err
res.status(500).send "An error occured"
else
if !fileInfo[3] or fileInfo[3] == "png"
ct = "image/png"
else if fileInfo[3] == "jpg"
ct = "image/jpg"
opts =
lastModified: false
headers:
"Content-Disposition": "inline; filename=\"#{file}\""
"Content-Type": ""
return router
I get the following error
/home/kindlyfire/Webroot/uplimg-server/src/web/view.coffee:24:9: error: unexpected if
if fs.access config.destination + file, fs.F_OK, (err) ->
^^
I looked at the spaces, no problem there. Has anybody an idea about what it might be ?
What you wrote is not valid coffeescript. Specifically, it is the commas on the line the error is pointing you to. I'd offer info on how to fix it, but I can't even tell what you were trying to accomplish here. You have to provide a way for the compiler (not to mention readers) to be able to tell, unambiguously, what divisions you want in your code:
# fine
if foo then (a, b) -> c
# also fine
if foo
(a, b) ->
c
# ??
if foo (a, b) -> c
# ????
if foo a, b -> c
Repro of the bug. Note that this is a good example of how to make a minimum reproduction of the problem. I highly, highly recommend you read a coffeescript style guide and discipline yourself to follow it. Which one is not terribly important, its the consistency that matters. Do not just randomly copy-paste stuff from the internets into your code, re-write it to follow the same style as the rest of your code. Doing so will often have the added benefit of realizing how the snippet you copied is working.

CoffeeScript Hubot help: getting data from a function

I'm a novice in need of some Hubot/CoffeeScript help.
I have several responses which will get data from the same source but use and respond to different pieces of the payload. For example...
module.exports = (robot) ->
robot.hear /score/i, (msg) ->
score = getScore(today)
msg.send "today's score is " + score
robot.hear /yesterday's score/i, (msg) ->
score = getStore(yesterday) ->
msg.send "yesterday's score was " + score
The process of building the URL for the score data includes looking up the current month, day and year. I don't want to do that more than once but I will have many responses like the above which use the same data. I had expected I could do this.
getScore = (day) ->
#build the url and get the data set
#pick the right piece of data based on the day variable and assign it to score'
I guess this doesn't work because it's async. But, doing msg.send from within the getScore function doesn't work. So, how do I do this so that I don't have to repeat the getScroe code in every robot.hear section?
Thanks!
Pseudo code:
getScore = (day, callback) ->
# get the score...
callback(score)
robot.hear /yesterday's score/i, (msg) ->
getScore "yesterday", (score) ->
msg.send "yesterday's score was " + score

Writing specs for Atom editor

I'm trying to write a simple package for Atom.io editor. This is my first experience with Coffeescript.
So I'm probably missing something trivial.
Anyway, this is my index.coffee
module.exports =
activate: ->
atom.workspaceView.command "md-utils:unorderedList", => #unorderedList()
unorderedList: ->
out = ""
editor = atom.workspace.activePaneItem
selection = editor.getSelection()
lines = selection.getText().split "\n"
for line in lines
out += "- " + line + "\n"
console.log(lines)
selection.insertText(out)
And here it is my index-spec.coffee
{WorkspaceView} = require 'atom'
describe "Markdown Utilities", ->
[editor, editorView] = []
unorderedList = (callback) ->
editorView.trigger "md-utils:unorderedList"
runs(callback)
beforeEach ->
atom.workspaceView = new WorkspaceView
atom.workspaceView.openSync()
editorView = atom.workspaceView.getActiveView()
editor = editorView.getEditor()
describe "when text is selected", ->
it "formats it correctly", ->
console.log = jasmine.createSpy("log")
editor.setText """
a
b
c
d
"""
editor.selectAll()
unorderedList ->
expect(console.log).toHaveBeenCalled()
expect(editor.getText()).toBe """
- a
- b
- c
- d
"""
Now, when I run the spec looks like the method in the index.coffee is not even called.
Both expectations failed :
Expected spy log to have been called.
Expected 'a b c d' to be '-a -b -c -d"
The method in itself works , so I do not understand why test fails.
Any suggestion is much appreciated
Actually your specs lack of a package activation, which is generally done with something like this:
beforeEach ->
atom.workspaceView = new WorkspaceView
atom.workspaceView.openSync()
editorView = atom.workspaceView.getActiveView()
editor = editorView.getEditor()
# Package activation is done within a promise so this will wait for the end of it
# before actually running the tests.
waitsForPromise -> atom.packages.activatePackage('your-package-name')
As your package is never activated, the command you define in the activate method is never registered, so the event triggered in your unorderedList helper never reach it.

What is the equivalent of apply(this, arguments) in coffeescript?

In javascript you would write something like:
method.apply(this,arguments);
However, how do you translate it to coffeescript?:
method.apply(#, arguments)
Is there a different name for the arguments variable?
Using splats you can use the cleaner coffeescript syntax:
caller: ->
#method arguments...
The above compiles to the following Javascript:
caller: function() {
return this.method.apply(this, arguments);
}
argumentsis available in coffee-script, too. So you can do:
method.apply #, arguments
If you want it to work exactly like javascript, you probably could, but coffeescript has "splats" for what you are probably trying to accomplish. Here's the explanation from coffeescript.org:
gold = silver = rest = "unknown"
awardMedals = (first, second, others...) ->
gold = first
silver = second
rest = others
contenders = [
"Michael Phelps"
"Liu Xiang"
"Yao Ming"
"Allyson Felix"
"Shawn Johnson"
"Roman Sebrle"
"Guo Jingjing"
"Tyson Gay"
"Asafa Powell"
"Usain Bolt"
]
awardMedals contenders...
alert "Gold: " + gold
alert "Silver: " + silver
alert "The Field: " + rest

How do I declare a variable in a specific scope in coffeescript?

I'm trying to write a jasmine test in coffeescript that uses a beforeEach block. This runs into a problem with coffeescript's variable scoping. Here's what I'd like to write:
describe 'PhoneDetailCtrl', () ->
beforeEach () ->
scope = angular.scope()
$browser = scope.$service('$browser')
it 'should fetch phone detail', () ->
scope.params = {phoneId:'xyz'}
$browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'})
ctrl = scope.$new(PhoneDetailCtrl)
expect(ctrl.phone).toEqualData({})
$browser.xhr.flush()
expect(ctrl.phone).toEqualData({name:'phone xyz'})
This doesn't work, though, because the scope and $browser will get declared with var in the innermost scope. That is, once in the beforeEach and then again in the it block. I can force the variables to be declared in the right scope by initializing them, but this seems very strange:
describe 'PhoneDetailCtrl', () ->
$browser = {}
scope = {}
beforeEach () ->
scope = angular.scope()
$browser = scope.$service('$browser')
it 'should fetch phone detail', () ->
scope.params = {phoneId:'xyz'}
...
This works, but the javascript it compiles to is actually
describe('PhoneListCtrl', function() {
var $browser, ctrl, scope;
$browser = {};
ctrl = {};
scope = {};
where all I need is the line var $browser, ctrl, scope;. Can I write this more concisely in coffeescript?
You are doing it the right way.
This is described in the CoffeeScript documentation. I wouldn't worry about the JS that it creates. Yes, it is a bit messy if you were to write it yourself, but this is one of the things that you have to live with when you use a re-writer like CoffeeScript.
You do, however, have a couple of options which are pretty nice.
You can put the variables in the current context if you wish (which happens to be your jasmine.Spec object for the curious, so it is a relatively safe and appropriate place to be putting variables... just don't overwrite existing vars in the context.):
describe 'PhoneDetailCtrl', () ->
beforeEach () ->
#scope = angular.scope()
#$browser = #scope.$service('$browser')
it 'should fetch phone detail', () ->
#scope.params = {phoneId:'xyz'}
#... etc
You can also setup your own variable in which to store things
describe 'PhoneDetailCtrl', () ->
setup = {}
beforeEach () ->
setup.scope = angular.scope()
setup.$browser = setup.scope.$service('$browser')
it 'should fetch phone detail', () ->
setup.scope.params = {phoneId:'xyz'}
#... etc
Your test could be written like the following:
describe "MyGame", ->
mygame = null
beforeEach inject (_MyGame_) ->
mygame = _MyGame_
it "should have two players", ->
expect(mygame.opponents.length).toEqual 2
Much cleaner syntax - without the need to make things global.