While git sub-tree merge strategy works great for merging a library into vendor (when you want to pull HEAD on that library instead of waiting for releases), I had trouble finding documentation on pushing back to upstream. This is annoying because one of the most obvious times you may want to use subtree is when you manage the library yourself, so can just pull straight from the repo, and want to push your maintenance changes back.
Surprisingly, and not what I have come to expect from git, it just works. From the example in the docs I linked, when you are checked out on master
git merge --squash -s subtree --no-commit rack_branch
will merge the rack_branch into where you have specified. But it just works the other way to. If checked out on rack_branch
git merge --squash -s subtree --no-commit master
will do what you expect, so you can now just push your library branch back to it’s upstream.
Awesome!
I am honored that you have chosen me to be your wife. You: the best person I know, my dearest friend, the highlight of my day.
I may have doubts and questions about life, but of you and this marriage I have none - it is the most fulfilling work of my life.
The sounds of your voice and the touch of your hand assures me that I am, at last, home, and I cannot wait to spend the rest of my life with you.
I love you now and always.
Some of you know that we aren’t very traditional and aren’t sold on the cultural expectations of marriage. We decided we’d try and have a kid before we decided to get married and we live as if we are married: we live together, share our expenses, daily life, hopes, dreams, and plans. Yet, I very much wanted to have a wedding and get married.
I want to commit so absolutely that Roula can feel it incarnated on her finger. I want her to have a constant reminder that I am here for her, at all times, and I want the same for me. I want to gather our loved ones and have them share a moment where we formalize our commitment. I want to crystalize and distill this moment down for all eternity, for us to share and remember when we are 102 and and hobbling down to the park for a Sunday picnic. I want to make the implicit, explicit, and for us to say out loud, in front of witnesses, the things we already both know and feel.
I promise to love and treasure you always, in sickness and in health, in poverty and in wealth;
to be considerate of your feelings, kind in all things, and ask forgiveness when I fail at that;
to talk through the tough times and always remember to the good ones;
to hold you above all others in my heart.
This I vow: to commit to this marriage with all my being and no reservations.
This article is a guide to writing unobtrusive JavaScript. It’s not always easy for people to transition to writing JavaScript this way, so I’ve tried to address common concerns.
The techniques presented here should enable you to think differently about client-side code and work more productively.
It’s important to realise that unobtrusive JavaScript is an evolving concept, perhaps even a movement. The broad goal is to separate JavaScript into a behaviour layer, but related goals include: enhancing browser behaviour, capability detection, and transparently supporting modern platforms like touchscreen phones.
This article was inspired by my surprise at the following tweets:
almost two months later, I’m still have trouble swallowing the UJS kool-aid. @jamis
Funny how the JS people get all shocked and dismayed when jamis complains about UJS. Evidence of kool-aid. @rjs
Unobtrusive JavaScript isn’t a fad, it’s how you should write JavaScript. If you read this blog, you’re probably doing it already. If you have server-side developer friends who don’t write much client-side code, please send them this article!
I don’t advocate blindly applying the techniques championed by the proponents of unobtrusive JavaScript. However, I have learned lessons from several hard-won battles which have enabled me to write JavaScript more productively — my own practices have evolved towards unobtrusive JavaScript over the last 4-5 years.
Where does inline JavaScript come from? One common place is server-side frameworks. It’s easier for frameworks to inject JavaScript through helpers — popular frameworks like Rails do this. This is because the HTML and JavaScript these frameworks generate is naturally tightly coupled. It’s also because the framework builders often try to appeal to the host language rather than seasoned JavaScript developers.
Inline JavaScript crops up in several places:
onclick are added to page elements through attributesscript tagsThese techniques work well for frameworks and make life easy for the host language developer. In fact, Rails is one of the projects that helped JavaScript frameworks bring Ajax to the world, and also the now ubiquitous use of visual effects through projects like Scriptaculous.
The alternative isn’t just about moving your JavaScript into its own files. It’s to change the way you think about JavaScript, the DOM, and HTML templates.
If you’ve worked with CSS, you’ll be familiar with the separation of style from structure through the use of stylesheets. The popular argument for writing unobtrusive JavaScript is that scripts define a behaviour layer, and therefore should be separated, just like stylesheets.
This is true up to a point, but it takes a leap of faith to get there. The key is to stop thinking about templates like static blocks of HTML, and see documents for what they are: living, breathing tree structures of DOM objects, events, and styles.
The main concern of those who are uncomfortable with writing unobtrusive JavaScript is maintainability. This is deeper than just finding code, or the link between a template and a script — it also affects project management.
When planning new features, it can be difficult to determine what page elements will be affected by a change if all of the JavaScript is outside the templates.
Or is it?
People resist writing JavaScript this way is because their mental model of a HTML document is based on HTML templates. A more useful mental model is one which encapsulates the true nature of the DOM — a document is a collection of interrelated objects, affected by scripts, stylesheets and their very structure.
When I start work on a new project or feature, I think in terms of these objects and how they’re related. I try to group like items and behaviours — just as styles can be efficiently shared, events can also.
This is what makes healthy client-side code possible. DOM ready lets you run a function when the document is in a usable state. This allows you to safely bind event handlers. In jQuery it looks like this:
$(document).ready(function() { // Your code here });
Prototype:
document.observe("dom:loaded", function() { // Your code here });
This isn’t actually an easy thing to write from scratch — let the framework do the work. I’ve written my own DOM ready handler before and it wasn’t much fun (mainly due to IE).
If you’ve come to JavaScript through jQuery, you might be wondering what I’ve been talking about. People raised on jQuery think in terms of event delegation, and this is one of the key strategies to writing unobtrusive JavaScript.
Event delegation is where an event is bound to a containing element, then conditionally executed based on the event’s element.
Imagine if you wanted to open popup windows when the user clicks a link. You could attach an onclick attribute and set up a window. Every link would then have to repeat this code.
An alternative approach is to use event delegation to bind an event to a high level element, the use a class to trigger a special popup event handler:
$(document).click(function(event) { if ($(event.target).is('.popup') { // Open a new window with specified parameters } event.preventDefault(); });
The benefit is similar to the benefits brought in by stylesheets — you can now change the behaviour of all popup windows across your entire project. You could even have multiple class names for different window properties — sizes, toolbar hiding, whatever! It also makes the page size smaller, all for the price of one event handler with an if statement.
On larger projects I use a technique that maps controllers to JavaScript objects. I do this by using body ID tags and classes. A function runs when the DOM is ready and calls the appropriate object.
For example, let’s say you’re making a blog application in Rails (or similar) and you have an ArticlesController. I’d use a helper in my Rails layout to create an appropriate body tag:
<%= body :id => controller.name %>
Which is defined like this:
def body(options = {}) tag 'body', options, true end
Then my JavaScript delegation function would look at the body tag and call a method on an associated object:
ArticlesController = { run: function() { // Do stuff that the articles templates need } }; $(document).ready(function() { var controllerName = ''; if ($('body').id) { controllerName = $('body').id + 'Controller'; if (typeof controllerName !== 'undefined') { controllerName['run'](); } } });
This body ID delegation pattern has allowed me to build very large Rails projects without feeling lost when moving between JavaScript and Rails templates. I also use body class names for shared functionality. The JavaScript “controllers” are generally stubs that invoke other objects.
Any framework could use this technique — it’s really just an agreement between your server-side code and JavaScript.
When I start writing JavaScript for a project, I try to think in terms of the core functionality, independent of the browser. I’ll write console-based code and run unit tests in the console. Once I’m happy with my “models” I’ll start to hook up event handlers.
Get used to thinking about events through CSS classes — try to group like events and rely on high-level delegated event handlers. Not only does this result in fast UI code, it also makes testing easier.
Good code us usually easy to test. I’ve found that writing light event handlers then calling higher-level objects helps keep testing simple and increases reusability.
It’s useful to be fully-versed in JavaScript’s object model and prototypal inheritance. Even though you can use certain libraries to ape classical OO, good code comes from a deep understanding of the tools at hand.
Maintainable and clear code comes from knowing when to exploit JavaScript’s flexible object system, rather than trying to write in a style that doesn’t suit it.
Keeping JavaScript out of templates can help:
To ensure projects are maintainable:
The ever useful rack-test gem let’s you easily integration test any rack project. All you have to do is include the Rack::Test::Methods and define an app method that returns your rack app. So people usually have a config.ru that just references their my_application.rb that they reference in their config.ru and then in their test file they can also reference that app and return it. Something to to this effect:
1 2 3 4 5 |
class MySweetRackApp
def initialize
Proc.new { |env| [200, {‘Content-Type’ => ‘text/html’}, [‘success’]] }
end
end
|
I had a project where I was actually trying to better breakdown a more complex app, and I wanted to just be able to use Rack’s built-in map method at the top level of my config.ru to route to different apps. And in at least some of the cases I wanted to be able to test the whole thing. Also, I figured sometimes it’s useful to actually be able to test your rackup file itself, all routing/mapping included. So I dug around in the rack code and found how the rackup command handles the .ru file, and came up with this:
If you use an authenticated_system on your Rails site, with global before_filters for things like requiring login to access pages, be careful of missing formats in the respond_to. I just tracked down a bug on an app where we were getting DoubleRenderErrors because of unauthenticated request directly to a csv file. We had a before_filter that was denying request and redirecting them to login, in different ways, depending on the format, but hadn’t thought to include csv. In this case, it is wise to include a catch-all at the end using .any
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
def anon_access_denied
respond_to do |accepts|
accepts.html do
store_location
redirect_to login_path
end
accepts.xml do
headers[“Status”] = “Unauthorized”
headers[“WWW-Authenticate”] = %(Basic realm=”Web Password”)
render :text => “Could’t authenticate you”, :status => ‘401 Unauthorized’
end
accepts.js do
render(:update) { |page| page.redirect_to login_path }
end
end
end
|
Basically, you just want to be very careful properly escaping and ending color sequences in your bash prompt. If you mess them up, when you try to use spiffy bash tricks that mess with your current line, such as control-r to search through your bash history and then left of right arrow to edit that line, you’ll get a partially overwritten line that is impossible to read or edit properly.
1 2 3 4 5 6 7 8 9 10 11 | #Just be careful. Safest to properly end color sequence, so instead of this
#export PS1=”\[\033[01;32m\]\u\[\033[00m\]\[\033[01;31m\]\$(git_br)\[\033[01;32m\]\[\033[00m\]:\[\033[01;36m\]\$(git_pwd)\[\033[00m\]\$ “
#do this
USER_GREEN=’\[\e[01;32m\]’
#NO_COLOR=’\[\e[00m\]’
REPO_RED=’\[\e[01;31m\]’
PATH_BLUE=’\[\e[01;36m\]’
END_COLOR=‘\e[m’
PS1=”${USER_GREEN}\u${END_COLOR}${REPO_RED}\$(git_br)${END_COLOR}:${PATH_BLUE}\$(git_pwd)${END_COLOR}$ “
|