While working on spec'ing out this merb-service-example app I came to a point where I had a lot of repetitive code, enough that I really wanted to DRY it up a bit. Long story short, after talking with David Chelimsky for a bit, I ended up with this: gists_spec.rb
I think the it_should_respond_with and it_should_return methods work well for adding clarity, reducing repetition, and making the specs even stronger. Still, I'm a bit unhappy with the method names. Some other possibilities thrown out there are:
Nothing feels perfect yet...and maybe it doesn't need to be...but, that's never stopped me from trying. What name(s) do you like? Any better suggestions?
Wednesday, November 12, 2008
Get over yourself and write that test
I've had to tell myself this a bit recently...and it wasn't the medium you'd expect.
I'd been working on a particularly tricky Sudoku puzzle...you know the kind where you've got lots of squares completely solved, and yet some are mostly blank? No matter what I did, I couldn't find a damn 7,8, or 9 to set off a finishing chain of selections. I also have this stubbornness that forces me to try and solve the hard puzzles without using notes. I almost always can, and yet this particular puzzle was besting me.
Its ok, I just have to try harder, right? Focus more, go over the various possibilities, what could this being here mean, and so on. Another 20 minutes pass and no progress. With a sigh I finally gave up, and started sketching out all of the possibilities. Within 3 seconds of doing so, I saw an obvious selection I had missed. This set off another, and another. 2 minutes later I was done.
Part of me felt like I "cheated"--any great Sudoku solver wouldn't need such help, right? At the same time, there's a point where the challenge of solving the puzzle degrades into frustration and really a waste of my time, and in this case I had long overshot that mark.
Feel familiar yet?
I couldn't help smiling as I thought about this on the metro in this morning. It reminded me of every time I'd sit down to write some code, get it wrong, redo some things, get it right...and then find out I really didn't...and repeat this process until I'd finally write a few tests and voila, be done with it.
I remember back in college hearing these epic stories of masters who could code in C, top to bottom, and at the end magically compile things without error. I think of people I know who can jump into a presentation, test, interview, or module, and just get what they need done without a moment's hesitation or need of 'backup' or notes.
I used to be one of those people...but I think lots of us were, back in 5th grade, just excited to learn the next set of formulas or geometric equations. I'm not anymore, and I'm ok with that. There's a certain peace of mind, a certain relaxation I feel, when I have code that's spec'ed, tested, and banged on to the point where I own it, and not the reverse.
Something I think people don't say enough, even with the tons of discussions about tests: even if your tests suck, even if they mock too much, are too brittle, and perhaps miss some important cases, the knowledge of the code that you receive while writing those tests is extremely valuable. The investment in your own ability to write those tests is extremely valuable. Testing really is like working out, and I've slipped as of late (in both areas), and can feel it.
I made the decision recently to change both of these things, and just like getting back into the gym has given me more energy and I just feel better, getting back into writing some tests has reminded me just why we should do it in the first place.
I've been flexing this rebirth with a simple merb 1.0 service example app located at http://github.com/jackdempsey/merb-service-example/tree/master and you'll see its using the new request helper. I'd talk more about that, but wycats has done so already, so I'll just say: you really, really want to test this way as opposed to mocking everything out. It allows for a very fluid and flexible inner workings of your controller, while verifying things come back as they should.
PS: I even TDD'ed this post via a friend checking it. As you'd expect, I was shown several 'bugs' and issues. Thanks again Doug
I'd been working on a particularly tricky Sudoku puzzle...you know the kind where you've got lots of squares completely solved, and yet some are mostly blank? No matter what I did, I couldn't find a damn 7,8, or 9 to set off a finishing chain of selections. I also have this stubbornness that forces me to try and solve the hard puzzles without using notes. I almost always can, and yet this particular puzzle was besting me.
Its ok, I just have to try harder, right? Focus more, go over the various possibilities, what could this being here mean, and so on. Another 20 minutes pass and no progress. With a sigh I finally gave up, and started sketching out all of the possibilities. Within 3 seconds of doing so, I saw an obvious selection I had missed. This set off another, and another. 2 minutes later I was done.
Part of me felt like I "cheated"--any great Sudoku solver wouldn't need such help, right? At the same time, there's a point where the challenge of solving the puzzle degrades into frustration and really a waste of my time, and in this case I had long overshot that mark.
Feel familiar yet?
I couldn't help smiling as I thought about this on the metro in this morning. It reminded me of every time I'd sit down to write some code, get it wrong, redo some things, get it right...and then find out I really didn't...and repeat this process until I'd finally write a few tests and voila, be done with it.
I remember back in college hearing these epic stories of masters who could code in C, top to bottom, and at the end magically compile things without error. I think of people I know who can jump into a presentation, test, interview, or module, and just get what they need done without a moment's hesitation or need of 'backup' or notes.
I used to be one of those people...but I think lots of us were, back in 5th grade, just excited to learn the next set of formulas or geometric equations. I'm not anymore, and I'm ok with that. There's a certain peace of mind, a certain relaxation I feel, when I have code that's spec'ed, tested, and banged on to the point where I own it, and not the reverse.
Something I think people don't say enough, even with the tons of discussions about tests: even if your tests suck, even if they mock too much, are too brittle, and perhaps miss some important cases, the knowledge of the code that you receive while writing those tests is extremely valuable. The investment in your own ability to write those tests is extremely valuable. Testing really is like working out, and I've slipped as of late (in both areas), and can feel it.
I made the decision recently to change both of these things, and just like getting back into the gym has given me more energy and I just feel better, getting back into writing some tests has reminded me just why we should do it in the first place.
I've been flexing this rebirth with a simple merb 1.0 service example app located at http://github.com/jackdempsey/merb-service-example/tree/master and you'll see its using the new request helper. I'd talk more about that, but wycats has done so already, so I'll just say: you really, really want to test this way as opposed to mocking everything out. It allows for a very fluid and flexible inner workings of your controller, while verifying things come back as they should.
PS: I even TDD'ed this post via a friend checking it. As you'd expect, I was shown several 'bugs' and issues. Thanks again Doug
Tuesday, November 11, 2008
Installing Merb 1.0 on Debian
This has come up a few times in #merb: as a result of the webrat and nokogiri dependencies, if you're looking to install 1.0 on a Debian box, make sure you have the following packages installed:
libxml-ruby libxslt-ruby libxml2 libxslt1-dev
Thanks to mr-interweb and maxbaroi for some late night detective work. The relevant ticket is located at http://merb.lighthouseapp.com/projects/7433-merb/tickets/986-webrat-is-required-for-merb-core-app-running-in-console#ticket-986-14
libxml-ruby libxslt-ruby libxml2 libxslt1-dev
Thanks to mr-interweb and maxbaroi for some late night detective work. The relevant ticket is located at http://merb.lighthouseapp.com/projects/7433-merb/tickets/986-webrat-is-required-for-merb-core-app-running-in-console#ticket-986-14
Wednesday, November 5, 2008
acts_as_commentable
Recently I've been looking over my various github projects, and am trying to give some love to things I haven't touched in a while. First up: acts_as_commentable.
A small amount of history first: the plugin was originally developed at http://www.juixe.com/techknow/index.php/2006/06/18/acts-as-commentable-plugin/
There've been many comments on it since then. My original intention was to port it over to something we could use in Merb. Turns out that actually didn't require much...actually, it was basically just an extra require in the library. I've touched things up a bit and have updated the repo at http://github.com/jackdempsey/acts_as_commentable/tree/master
I've sent an email to the original author as I'm not trying to pirate his/her stuff...we'll see what comes of that, but I noticed the other day that there were 54 or so watchers (and on a tangent--I mentioned that in #github and this might have sparked some ideas along the line of being able to easily see who's watching your repos), so hopefully those who're interested can play with things, and finally have a vehicle to contribute if desired.
Please feel free to send me comments, patches, etc. Something this widely used is just being for community support and feedback.
A small amount of history first: the plugin was originally developed at http://www.juixe.com/techknow/index.php/2006/06/18/acts-as-commentable-plugin/
There've been many comments on it since then. My original intention was to port it over to something we could use in Merb. Turns out that actually didn't require much...actually, it was basically just an extra require in the library. I've touched things up a bit and have updated the repo at http://github.com/jackdempsey/acts_as_commentable/tree/master
I've sent an email to the original author as I'm not trying to pirate his/her stuff...we'll see what comes of that, but I noticed the other day that there were 54 or so watchers (and on a tangent--I mentioned that in #github and this might have sparked some ideas along the line of being able to easily see who's watching your repos), so hopefully those who're interested can play with things, and finally have a vehicle to contribute if desired.
Please feel free to send me comments, patches, etc. Something this widely used is just being for community support and feedback.
Sunday, November 2, 2008
useful snippets
I rely on a number of aliases, shell scripts, and whatever time savers I can come up with. You never know what you might learn by seeing someone elses, so here's a few of my favorites:
I've mentioned the cdargs stuff before, and there's a great post talking about git bash completionfor those interested.
k, now it's your turn.
I've mentioned the cdargs stuff before, and there's a great post talking about git bash completionfor those interested.
k, now it's your turn.
Monday, October 20, 2008
Creating a new Merb stack with Templater
In trying to remove Merb's dependency on ActiveSupport, Jonas Nicklas developed Templater. I'm going to show you briefly how to use it to create an ActiveRecord, TestUnit, and Prototype based Merb stack.
I'd like to make clear at this point that this is more for learning about Merb, generators, and to use as a reference point for creating other stacks. I prefer DataMapper, Rspec, and JQuery, and as such this example stack won't be supported officially or unofficially (unless someone else would like to...if so, let me know).
You can find the code here: http://github.com/jackdempsey/merb-ar-stack/tree/master
The first important piece is the Generators file:
This file is picked up by Templater and as such, when merb-gen is run, you'll see it listed as one of the available generators. Lets take a look at what merb_ar_stack actually is then.
merb-ar-stack/lib/generators/merb_ar_stack.rb
Pretty straightforward, right? You'll see a couple places easily configured to be whatever you like, as well as listing of various files you want to include (like the prototype.js reference).
Beyond that, you'll see inside lib/generators/templates an application directory that holds a directory for the common files you'll use as well as a directory that actually lays out what the generated app will look like.
The final important piece is inside the Rakefile:
This array is used later in the rake file by add_dependency. It takes care of bringing in the various gems needed for your stack. Take a look here to see what the official stack depends upon.
Thats pretty much it. There are other pieces that you'll want to configure things (like in the config/init.rb file inside your templates/application/merb_ar_stack folder for instance). I'd recommend forking this repo and tinkering with things a bit to get a feel for how it all fits together.
Things have been a bit busy recently, so I haven't had as much time for blogging as I'd like. I hope to write more in the near future when 1.0 is out and people are looked to really dig into things.
I'd like to make clear at this point that this is more for learning about Merb, generators, and to use as a reference point for creating other stacks. I prefer DataMapper, Rspec, and JQuery, and as such this example stack won't be supported officially or unofficially (unless someone else would like to...if so, let me know).
You can find the code here: http://github.com/jackdempsey/merb-ar-stack/tree/master
The first important piece is the Generators file:
scope 'merb-gen' do
dir = File.join(File.dirname(__FILE__), 'lib', 'generators/')
Merb.add_generators dir + 'merb_ar_stack'
end
This file is picked up by Templater and as such, when merb-gen is run, you'll see it listed as one of the available generators. Lets take a look at what merb_ar_stack actually is then.
merb-ar-stack/lib/generators/merb_ar_stack.rb
module Merb
module Generators
class MerbArStackGenerator < AppGenerator
#
# ==== Paths
#
def self.source_root
File.join(super, 'application', 'merb_ar_stack')
end
def self.common_templates_dir
File.expand_path(File.join(File.dirname(__FILE__), 'templates', 'application', 'common'))
end
def destination_root
File.join(@destination_root, base_name)
end
def common_templates_dir
self.class.common_templates_dir
end
def testing_framework
:test_unit
end
def orm
:activerecord
end
#
# ==== Generator options
#
option :template_engine, :default => :erb,
:desc => 'Template engine to prefer for this application (one of: erb, haml).'
desc <<-DESC
This generates a "prepackaged" (or "opinionated") Merb application that uses ActiveRecord,
TestUnit, helpers, assets, mailer, caching, slices and merb-auth all out of the box.
DESC
first_argument :name, :required => true, :desc => "Application name"
#
# ==== Common directories & files
#
empty_directory :gems, 'gems'
file :thorfile do |file|
file.source = File.join(common_templates_dir, "merb.thor")
file.destination = "tasks/merb.thor"
end
template :rakefile do |template|
template.source = File.join(common_templates_dir, "Rakefile")
template.destination = "Rakefile"
end
file :gitignore do |file|
file.source = File.join(common_templates_dir, 'dotgitignore')
file.destination = ".gitignore"
end
file :htaccess do |file|
file.source = File.join(common_templates_dir, 'dothtaccess')
file.destination = 'public/.htaccess'
end
file :doctask do |file|
file.source = File.join(common_templates_dir, 'doc.thor')
file.destination = 'tasks/doc.thor'
end
file :prototype do |file|
file.source = File.join(common_templates_dir, 'prototype.js')
file.destination = 'public/javascripts/prototype.js'
end
directory :test_dir do |directory|
dir = testing_framework == :rspec ? "spec" : "test"
directory.source = File.join(source_root, dir)
directory.destination = dir
end
#
# ==== Layout specific things
#
# empty array means all files are considered to be just
# files, not templates
glob! "app"
glob! "autotest"
glob! "config"
glob! "doc", []
glob! "public"
glob! "lib"
glob! "merb"
invoke :layout do |generator|
generator.new(destination_root, options, 'application')
end
end
add 'ar-app', MerbArStackGenerator
end
end
Pretty straightforward, right? You'll see a couple places easily configured to be whatever you like, as well as listing of various files you want to include (like the prototype.js reference).
Beyond that, you'll see inside lib/generators/templates an application directory that holds a directory for the common files you'll use as well as a directory that actually lays out what the generated app will look like.
The final important piece is inside the Rakefile:
gems = [
["merb-core", "~> #{GEM_VERSION}"],
["merb-more", "~> #{GEM_VERSION}"],
["activerecord", "~> 2.1.0"]
]
This array is used later in the rake file by add_dependency. It takes care of bringing in the various gems needed for your stack. Take a look here to see what the official stack depends upon.
Thats pretty much it. There are other pieces that you'll want to configure things (like in the config/init.rb file inside your templates/application/merb_ar_stack folder for instance). I'd recommend forking this repo and tinkering with things a bit to get a feel for how it all fits together.
Things have been a bit busy recently, so I haven't had as much time for blogging as I'd like. I hope to write more in the near future when 1.0 is out and people are looked to really dig into things.
Tuesday, September 9, 2008
Thor finds Mjolnir
If you've been following the development of Thor, you'll know there's been a bug that affected commands with several layers of namespacing. Tonight I'm happy to announce this bug was finally crushed by Yehuda Katz.
Just to briefly describe the pain this has brought me, a few facts:
* Class.constants only gets the top level constants. If you have Foo::Bar::Baz, don't expect to see Baz in Foo.constants
* Struct is mean:
(You can imagine how the first point led me to the second, right? Yeah...fun.
* Remember, when you ask for constants on a class, it:
It _also_ returns constants defined in any class you inherit from.
So, lets just say this all added up to a nice bit of hacking for me, and truthfully it was a good experience. It started to get old after a while, but I think this is something people don't talk about enough. Its the same with lifting weights: you purposely destroy and rip apart your muscles so they can build up bigger and stronger next time.
If you don't at least semi-often tackle hard problems, frustrating situations, and just fight through those moments when you think "screw it, PHP isn't that bad", you'll never get the kind of experience that really makes you grow as a Rubyist, and really, a programmer. You'll often find at the end not only did you learn some new tricks, but sometimes the solution is right there before your eyes....or Yehuda's eyes...but still, you'll get a lot out of it.
So anyway, I'm happy to point people to http://github.com/wycats/thor/tree/master and say 'Enjoy!' The soon to come Merb bundling tasks will be taking advantage of Thor's power, so if you haven't done anything with Thor yet, now's a great time to jump on board.
Just to briefly describe the pain this has brought me, a few facts:
* Class.constants only gets the top level constants. If you have Foo::Bar::Baz, don't expect to see Baz in Foo.constants
* Struct is mean:
(You can imagine how the first point led me to the second, right? Yeah...fun.
* Remember, when you ask for constants on a class, it:
Returns an array of the names of the constants accessible in mod. This includes the names of constants in any included modules (example at start of section).It _also_ returns constants defined in any class you inherit from.
So, lets just say this all added up to a nice bit of hacking for me, and truthfully it was a good experience. It started to get old after a while, but I think this is something people don't talk about enough. Its the same with lifting weights: you purposely destroy and rip apart your muscles so they can build up bigger and stronger next time.
If you don't at least semi-often tackle hard problems, frustrating situations, and just fight through those moments when you think "screw it, PHP isn't that bad", you'll never get the kind of experience that really makes you grow as a Rubyist, and really, a programmer. You'll often find at the end not only did you learn some new tricks, but sometimes the solution is right there before your eyes....or Yehuda's eyes...but still, you'll get a lot out of it.
So anyway, I'm happy to point people to http://github.com/wycats/thor/tree/master and say 'Enjoy!' The soon to come Merb bundling tasks will be taking advantage of Thor's power, so if you haven't done anything with Thor yet, now's a great time to jump on board.
Subscribe to:
Posts (Atom)
