layout false if request.xhr?

Posted by Justin Reagor Mon, 13 Jul 2009 14:30:00 GMT

Rather simple actually… since ActionController::Base.layout takes a proc, and calls it upon a request.

class ApplicationController < ActionController::Base
  def self.without_layout_on_xhr
    layout proc { |controller| controller.in_popup? ? nil : "application" }
  end

  def in_popup?
    request.xhr?
  end
end

class BusyWorkController < ApplicationController
  without_layout_on_xhr

  before_filter :login_required

  def new
    @work = Busy.new
  end
end

I’ve abstracted out the conditions for rendering without a template based on the controller instance method #in_popup?. Feel free to change it to whatever you want.

Good things come to he who waits 2

Posted by Colin A. Bartlett Tue, 05 May 2009 18:31:00 GMT

When the merger of Merb and Rails was announced a few months ago, I don’t think anyone really expected the goal of having Rails 3 released at RailsConf to be met. Alas, it was not. But David announced today that much of the groundwork to combining the two frameworks has already been done. Most of the work has been behind the scenes refactoring—the kind of changes that developers will likely never notice. But other features that are in the codebase and coming soon include:

  • An all-new router, with an improve DSL that’s more merbish. It will include routing based on subdomains and user gents, and the ability to mount multiple apps side by side.
  • Since many developers aren’t consistently using the h() helper method to escape potential script injections, the default behavior will now be to escape everything except when an all-new raw() method is utilized.
  • Much of the code to make Rails JS framework agnostic is complete. New features include using data=remote=”true” and data-method=”delete” (which validate in HTML5) to allow unobtrusive binding of JS events.

David equated the new Rails philosophy to Burger King’s “Have it Your Way” concept. If I want a great burger, I can order a Whopper. But, if I have specific tastes, I can order it without pickles. Or with extra ketchup. Rails will allow you to get a great framework out of the box for users that just want it to work. But, for those that are passionate about a particular JS framework or other toolset, they can freely customize their Rails.

Toward the end of David’s keynote, he relayed a couple experiences he’s had. He reminded us to make sure that, as developers, we don’t accept the requirements bestowed upon us by stakeholders at face value. We need to constantly offer up alternatives and input. In his experience, many times when you relay to the stakeholder a different, sometimes lest costly, way to do things, their response is often: “Sure, whatever”.

This approach can save we developers hours of wasted time. That’s because, when stuck on a tough challenge, as time drags on, our motivation drops. We try to keep up our spirits but, when it looks like the challenge is impossible, we end up burning needless hours. We should quit at the point our mind checks out and reexamine the problem. David gave an example of a tough issue he worked on for two weeks and he explained that only a week and half of it he was really working and after that the rest was just goofing around because he already had given up. He should have gone back to stakeholders right then rather than burning a few more days with zero motivation.

Pathname of the Righteous 2

Posted by Justin Reagor Thu, 30 Apr 2009 00:25:00 GMT

Lately, I've noticed a lot of scripts taking advantage of File, Dir, FileUtils and even FileTest. Nothing odd, and these are fully warranted for most. They get the job done just fine, end of story.

But Ruby is special. Like little yellow bus special. It's about these things called Object instances, not Class/singleton methods. Maybe you'll agree with me, maybe you won't... but I'm sure you'll enjoy reading more about what Ruby is packaged to offer.

The Golden Child

Pathname is what this article is about. It's part of the standard library which comes included with MRI's Ruby distribution. You might have seen Pathname used like this...

require 'pathname'
$: << Pathname(__FILE__).dirname.join('lib', 'bacon', 'bits').to_s

...which is normally this...

$: << File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'bacon', 'bits'))

BTW: $: is called the "load path", I'm sure you've seen plenty of errors about it... read here

This is because Pathname represents a full file name path in your filesystem. Only as a Ruby Object instance. See what I mean? Using Ruby this way just makes you want to rub your tummy like Santa after cookies and milk.

Alil Deeper

Most people stop there. They say to themselves, "Man, that looks great but you're not really saving lines of code. I mean, you just daisy chain method calls and every time I use this I have to explicitly require it".

Thinking this way is just wrong, because "All functionality from File, FileTest, and some from Dir and FileUtils is included, in an unsurprising way. It is essentially a facade for all of these, and more".

What does this mean? Well, when you find some crazy file handling method...

def some_files
  @file_list = Dir.entries(DOC_PATH)
  @file_list.reject! { |entry| entry =~ /^\./ }
  @pretty_file_list = []
  @file_list.each do |file|
    file_path = File.join(DOC_PATH, file)
    if ! File.directory?(file_path)
      tmp = {}
      tmp[:name] = file
      tmp[:date] = File.ctime(file_path)
      tmp[:size] = sprintf("%.2f", (File.size(file_path) / 1.0.kilobytes)) + " kb"

      @pretty_file_list << tmp
    end
  end
  @pretty_file_list.sort! { |x,y| x[:date] <=> y[:date] }
end

You can refactor it like so...

def some_files
  @file_list = Pathname(DOC_PATH).children.
    delete_if(&:directory?).
    sort_by(&:ctime).inject([]) do |file|
      {
        :name => file.to_s,
        :date => file.ctime,
        :size => sprintf("%.2f", (file.size / 1.0.kilobytes)) + " kb"
      }
    end
end

Personally, I would just pass around the actual Pathname instances without building this hash because Pathname provides an immense amount of convenience for handling files wrapped into one library.

The library uses this example...

require 'pathname'
p = Pathname.new("/usr/bin/ruby")
size = p.size              # 27662
isdir = p.directory?       # false
dir  = p.dirname           # Pathname:/usr/bin
base = p.basename          # Pathname:ruby
dir, base = p.split        # [Pathname:/usr/bin, Pathname:ruby]
data = p.read
p.open { |f| _ }
p.each_line { |line| _ }

With Strings

Just remember that Pathname returns instances, not Strings. So methods that use #to_s will work like normal.

puts Pathname('.').expand_path
=> "/home/justin/Kinetic/articles"

p Pathname('.').expand_path
=> #<Pathname:'/home/justin/Kinetic/articles'>

You can even concatenate String's to Pathname's to build a path, as you would between normal strings.

p1 = Pathname.new("/usr/lib")   # Pathname:/usr/lib
p2 = p1 + "ruby/1.8"            # Pathname:/usr/lib/ruby/1.8
p3 = p1.parent                  # Pathname:/usr
p4 = p2.relative_path_from(p3)  # Pathname:lib/ruby/1.8
pwd = Pathname.pwd              # Pathname:/home/gavin
pwd.absolute?                   # true
p5 = Pathname.new "."           # Pathname:.
p5 = p5 + "music/../articles"   # Pathname:music/../articles
p5.cleanpath                    # Pathname:articles
p5.realpath                     # Pathname:/home/gavin/articles
p5.children                     # [Pathname:/home/gavin/articles/linux, ...]

However, you will need to call #to_s. For instance, when adding to the load path array, which normally contains expanded path strings.

From up top, notice the #to_s...

$: << Pathname(__FILE__).dirname.join('lib', 'bacon', 'bits').to_s

But when you're requiring you won't need it.

require Pathname(__FILE__).dirname.join('lib', 'bacon', 'bits')

In Conclusion

So that's really it... when not to use Pathname? Well, you will want to check to make sure that alternative Ruby implementation support it. Classes like File and Dir definitely will be supported by many, but Pathname might not. Also, if you believe you'll be doing major binary work, heavy File CRUD or possibly need to extend File writing operations... please don't use this. I also believe Windows support has gotten better in Ruby 1.9.1, but its a little flacky in older versions. But who uses Windows?

Simple stuff really, but I hope to see more of you using this instead of all those File classes and their class method calls. Even when you need to do very few things with Pathname, just require it, because I'm sure you'll find some use for it later!

An Afternoon With Cappuccino 5

Posted by Justin Reagor Sat, 28 Mar 2009 19:16:00 GMT

Ok, so I know all about the Cocoa inspired, Javascript framework, SproutCore (with it's tiny bit of Ruby for the "build process"). It definitely has the leverage of being based on current web technologies. As well as used by Apple for the "highly successful" MobileMe service (hehe). While making excellent use of the fat client pattern.

However, I just tried out Cappuccino, by way of Objective-J, and ran through some tutorials. The power of the GNUstep/Cocoa frameworks are definitely something to be seen within your web browser.

I am starting to think I prefer this more for utilizing desktop applications on the web. In a similar vein as Java applets or Flash web apps. Because that's what Cappuccino and SproutCore were built for, desktop-like web applications. Not traditional "web sites" or hyper text documentation.

Short Intro

Objective-J is the language written using Javascript. Where Cappuccino is the framework built with Obj-J. A rewrite of Cocoa and GNUstep for the DOM.

The wiki defines Objective-J as...

... a programming language developed as part of the Cappuccino web development framework. Its syntax is nearly identical to the Objective-C syntax and it shares with JavaScript the same relationship that Objective-C has with the C programing language: that of being a strict, but small, superset; adding traditional inheritance and Smalltalk/Objective-C style dynamic dispatch to JavaScript. Pure JavaScript, being a prototype-based language, already has a notion of object orientation and inheritance, but Objective-J adds the use of class-based programming to JavaScript.

Taking a small look at some of the code you will see its heavy Obj-C syntax...

@import <Foundation/CPObject.j>   

@implementation AppController : CPObject {   
  CPTextField label;   
  CPString contentString;   
};   

- (void)applicationDidFinishLaunching:(CPNotification)aNotification {   
  var contentString = @"Hello world!";   
  var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask],   
  contentView = [theWindow contentView];   

  label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];   

  [label setStringValue:contentString];   
  [label setFont:[CPFont boldSystemFontOfSize:24.0]];   
  [label sizeToFit];
  [label setAutoresizingMask:CPViewMinXMargin |
                                                   CPViewMaxXMargin |
                                                   CPViewMinYMargin |
                                                   CPViewMaxYMargin ];
  [label setFrameOrigin:CGPointMake((CGRectGetWidth([contentView bounds]) - CGRectGetWidth([label frame])) / 2.0,
                                (CGRectGetHeight([contentView bounds]) - CGRectGetHeight([label frame])) / 2.0)];

  [contentView addSubview:label];
}
@end;

The Pros

No one is suggesting you to ditch your life as a strict web standards developer and embrace the auto-generated presentation layers that Cappuccino provides. Instead, embrace the tool (TWSS). Use it when its the most appropriate.

Here are the positive bits I can identify at first glance...

  • Utilizes a proven platform and framework for desktop applications, Cocoa and GNUstep
  • Automagic cross browser support; from everything being abstracted away from you.
  • Obj-J can have Javascript intermingled, so you can write in a style with a cross between the two (hence the J).
  • NO PLUGINS; They wrote the damn lexer/parser entirely in Javascript. That's not JS ignorance, that's talent.
  • It seems pretty snappy and fast.
  • Used in production, considering 280slides.com is a killer web app.
  • Obj-J command-line interpreter
  • Theme support coming
  • Rake now employed for the "build"

The Cons

I've read through a ton of grips, mostly the introduction on Ajaxian. It seems that people at first believed this was an insult to Javascript. That there wasn't much of a purpose in bringing Obj-C to the web since HTML/CSS/JS work just as well. Of course the same people say the same thing about Java and Flash... but anyway, here are a few I'm watching out for.

  • Layers of abstraction are a plus, and a minus. :<
  • Seems you can only leverage current web tech (HTML/CSS/Canvas) through Cappuccino/Cocoa objects.
  • I haven't experienced their inheritance model yet, so I'm hoping thats not a hinderness (as in creating your own NSTableView or whatever).
  • The HTML source is completely obfuscated, and I imagine you can't make use of the DOM (restricted to Obj-J classes)
  • No command console [IRB]? Haven't found one yet.
  • Some error messages are vague.
  • Test/Behavior driven development? OJUnit does exist, haven't checked it out though.

EOF

The fact that the W3C and the industry are going to take decades to complete HTML5 and full CSS3 compliant browsers demonstrates the viability of this framework. No plugins, no compilation, just run the damn apps is POWERFUL. Also, given the success of Apple's platforms so far, Obj-C is proving itself on the desktop and on the iPhone. It's definitely not the horror that is VB.

Given those I think all-in-all it's a wonderful technology and I look forward to building a few apps with it!

What It's Like To Work At Kinetic

Posted by Justin Reagor Wed, 11 Mar 2009 23:36:00 GMT

The only difference is we have tons of work to do! ;)

Upgrading Git on Mac OS X 5

Posted by Colin A. Bartlett Sat, 07 Mar 2009 13:11:00 GMT

We recently switched to git based capistrano deployments and I quickly found out that these weren’t working from my MacBook Pro. I noticed that my git version was a few behind my coworker’s, so I figured it was time to upgrade.

Following Justin’s original git compilation instructions, I downloaded and compiled the latest Git version, 1.6.2 like so:

curl -O http://kernel.org/pub/software/scm/git/git-1.6.2.tar.gz
tar jxvf git-1.6.2.tar.gz
cd git-1.6.2
make prefix=/usr/local all
make prefix=/usr/local test && echo $?
sudo make prefix=/usr/local install

When the compile was done, it gave me output like this:

!! You have installed git-* commands to new gitexecdir.
!! Old version git-* commands still remain in bindir.
!! Mixing two versions of Git will lead to problems.
!! Please remove old version commands in bindir now.

Thanks to this nice posting, I discovered this always happens when you upgrade to 1.6 and above. Git now only puts the main git binary and a few others in your /usr/local/bin and it tucks the rest away elsewhere. That meant that all the other zillion binaries needed to be deleted from my bin. I simply did:

cd /usr/local/bin/
ls -latr | grep git

Which gave me an ordered list of all the git binaries installed. The ones at the end all had today’s date on them, so I knew those were the new versions. The rest I could whack. The ones I could keep were git-upload-pack, git-upload-archive, git-receive-pack, git, git-shell, git-cvsserver, and gitk. The rest I removed like so:

sudo rm git-var git-update-server-info git-unpack-file git-ssh-upload git-ssh-push git-ssh-pull git-ssh-fetch git-show-index git-send-pack git-peek-remote git-patch-id git-pack-redundant git-mktree git-mktag git-merge-tree git-merge-recursive git-merge-index git-local-fetch git-index-pack git-imap-send git-http-push git-http-fetch git-hash-object git-fetch-pack git-fast-import git-daemon git-convert-objects git-bisect git-write-tree git-whatchanged git-verify-tag git-verify-pack git-update-ref git-update-index git-unpack-objects git-tar-tree git-tag git-symbolic-ref git-svnimport git-svn git-submodule git-stripspace git-status git-stash git-show-ref git-show-branch git-show git-shortlog git-sh-setup git-send-email git-runstatus git-rm git-revert git-rev-parse git-rev-list git-reset git-rerere git-request-pull git-repo-config git-repack git-remote git-relink git-reflog git-rebase--interactive git-rebase git-read-tree git-quiltimport git-push git-pull git-prune-packed git-prune git-parse-remote git-pack-refs git-pack-objects git-name-rev git-mv git-mergetool git-merge-subtree git-merge-stupid git-merge-resolve git-merge-ours git-merge-one-file git-merge-octopus git-merge-file git-merge-base git-merge git-mailsplit git-mailinfo git-ls-tree git-ls-remote git-ls-files git-lost-found git-log git-instaweb git-init-db git-init git-gui git-grep git-get-tar-commit-id git-gc git-fsck-objects git-fsck git-format-patch git-for-each-ref git-fmt-merge-msg git-filter-branch git-fetch--tool git-fetch git-diff-tree git-diff-index git-diff-files git-diff git-describe git-cvsimport git-cvsexportcommit git-count-objects git-config git-commit-tree git-commit git-clone git-clean git-citool git-cherry-pick git-cherry git-checkout-index git-checkout git-check-ref-format git-check-attr git-cat-file git-bundle git-branch git-blame git-archive git-archimport git-apply git-annotate git-am git-add--interactive git-add gitjour

Then I just had to go back and install the manpages for the new version like so:

curl -O http://kernel.org/pub/software/scm/git/git-manpages-1.6.2.tar.bz2
sudo tar xjv -C /usr/local/man -f git-manpages-1.6.2.tar.bz2

And, low and behold, I was now running git 1.6.2! What’s more, my capistrano deployments work now.

Older posts: 1 2 3 ... 22