I recently contributed some Emacs Lisp projects to MELPA. The process was pretty simple. I forked MELPA and created a file that pointed to my repo. Then after pushing to my fork, I submitted a pull request.
But I had a few issues where my code was emitting compiler warnings. Every time I pushed code to my emacs package repository with byte-compile warnings, I would have someone tell me to fix these warnings. So I got fed up with this and created some tests that verify no compiler warnings exist.
I linked this together with Travis CI so that whenever I push my changes, I run a full test suite for my Emacs Lisp and also make sure no warnings exist.
To setup Travis CI, I created this .travis.yml dotfile:
.travis.yml basically tells Travis CI to install a particular version of Emacs, then run "make test". Thats it. Here is what the makefile looks like:
The Makefile test target essentially runs all the tests under the test/ directory while using the .cask directory as a sandbox, which will have all the necessary emacs lisp packages installed for your project.
Now all you have to do is put tests under a test/ directory in your git project. Here is the test I use to verify my package builds with no warnings:
Now all you have to do is run make test under your emacs package repository and you can ensure you have no warnings that other people might run into when running package-install.
Since the makefile test target is dynamic, any test-file.el you put under the tests directory will now be run in Travis CI.
If you want to run them manually you can just run "make test/test-file.el". If you want to be really fancy, you can setup make test to be run as part of your git pre-commit hooks.
Hope this helps!
Thursday, November 12, 2015
Tuesday, October 27, 2015
Tying together custom knockout bindings
I ran across a problem recently where I had a bindingHandler that I wanted to depend upon other bindings on the same node.
Here is an example:
Knockout handles this for a normal bindingHandler in the update function. If the valueAccessor changes, update gets fired.
So I needed to have a way to get access to the valueAccessor of a different bindingHandler on the same node. The solution I came up with involved asking the knockout bindingProvider to give me the value accessors, then subscribing to the valueAccessor I wanted to listen to:
So now when the visible binding updates, we get the result of the valueAccessor instead of a single result at one point in time of a valueAccessor (shown in the first js code block).
I know this sounds complicated, but this was exactly what I was looking for to be able to access the valueAccessors of the same node. Using allBindings().someHandler was forcing me to make trivial pureComputed variables:
I really wanted this trivial code to exist in the template, not in the viewModel. So the solution using getBindingAccessors allows me to keep this code in the templates.
<div data-bind="myHandler, visible: !enabled()"> </div>So in general, you have access to all the other bindings when inside a bindinghandler:
ko.bindingHandlers.myHandler = { init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { var visible = allBindings().visible; } };The problem with calling allbindings().someBinding, is that you get the *result* of the binding. In my case, I wanted to subscribe to when any updates happen to the entire binding: "visible: !enabled()"
Knockout handles this for a normal bindingHandler in the update function. If the valueAccessor changes, update gets fired.
So I needed to have a way to get access to the valueAccessor of a different bindingHandler on the same node. The solution I came up with involved asking the knockout bindingProvider to give me the value accessors, then subscribing to the valueAccessor I wanted to listen to:
ko.bindingHandlers.myHandler = { init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { var bindingAccessors = ko.bindingProvider.instance.getBindingAccessors(element, bindingContext), visibleAccessor = bindingAccessors.visible, myObservable = viewModel.someObservable; // For complex reasons, this observable needs to update based on another binding in the same node if (visibleAccessor) { // This simulates what the knockout update bindingHandler does: ko.computed(function() { myObservable(ko.unwrap(visibleAccessor)); // the computed fires because we have visibleAccessor in our scope }); } } };
So now when the visible binding updates, we get the result of the valueAccessor instead of a single result at one point in time of a valueAccessor (shown in the first js code block).
I know this sounds complicated, but this was exactly what I was looking for to be able to access the valueAccessors of the same node. Using allBindings().someHandler was forcing me to make trivial pureComputed variables:
var MyViewModel = function() { this.enabled = ko.observable(false); this.disabled = ko.pureComputed(function() { return !this.enabled(); }, this); }
I really wanted this trivial code to exist in the template, not in the viewModel. So the solution using getBindingAccessors allows me to keep this code in the templates.
Wednesday, September 2, 2015
Add on-the-fly bindings in knockout
Let's say you want to add a special css class that you only need in a certain context in a certain template. Instead of defining the css class on the viewModel: this.extraCssClass = 'myClass'; Consider doing this:
What is happening here is that we use the with binding to call a function that installs extraCssClass on $context. Then we return $data to continue using the same $data scope with inner data-bind calls.
Then in template.mustache, you can consume the css class by checking $context:
I don't think this is *too* hacky, and it allows you inject custom variables without adding special logic to your viewmodel.
Let me know what you think!
<!-- ko with: function() { $context.extraCssClass = {'my-css-class': true}; return $data } --> {{ my/sub/template.mustache }} <!-- /ko -->
What is happening here is that we use the with binding to call a function that installs extraCssClass on $context. Then we return $data to continue using the same $data scope with inner data-bind calls.
Then in template.mustache, you can consume the css class by checking $context:
<div data-bind="css: $context.extraCssClass || {}"></div>
I don't think this is *too* hacky, and it allows you inject custom variables without adding special logic to your viewmodel.
Let me know what you think!
Subscribe to:
Posts (Atom)