Mr eel
Ruby
Getting the Rug Pulled From Under Your Feet
So, recently we’ve learned that Merb will be merged with Rails.
This is complete bullshit. I’m strongly opposed to the idea and I think it’s a huge mistake. I won’t enumerate all the reasons why — I think that’s all going to be thrashed to death in the coming days — but I do have a number of specific objections that I want to highlight.
Firstly, this means removing choice and competition between Merb and Rails, which despite the occasional friction, I considered to be a good thing. It doesn’t benefit the Ruby community to shift back to one monolithic framework.
I choose to use Merb for practical and philosophical reasons — basically it’s smaller, faster and easier to grasp as a whole. The development process has also always seemed more transparent and open to contributions from outside the core developers. It was a real viable choice to Rails.
But, what’s most irritating about this decision is the secrecy. There is a community of Merb users and developers who weren’t given a chance to comment on or participate in the choice. Instead we get one secretive clique schmoozing up with another secretive clique. It’s damned rude.
The end result is that the term Merb Community has no meaning to them. They don’t give a shit. If you ever used Merb, pimped it to clients or other developers, bought a Merb book, made a plugin, paid for training or went to Merb Camp — you’re being treated like a sucker. They’ve just given you a kick in the balls and you’re being told you’re gonna love it.
I’m damned bitter. I hate the idea and am disgusted at the lack of transparency and condecention implied in the decision.
I now have no interest in Merb at all. They can go to hell.
EDIT: For a good explanation of the merge, read this post by Matt Aimonetti. I’ve since tempered my views a little — although I’m still against the merge in principle and hate the secrecy surrounding the choice — Matt has helped put things into perspective.
A Content Management System That Doesn’t Annoy Me
I’ve used a fair amount of content management systems over the years. They’re all pretty awful. I won’t enumerate over all the reasons, since plenty of other grumpy people have done that already. Instead I thought I might highlight two of the main concerns I have when using a CMS.
I’m an Expert, Let Me Get All Experty
In other words, don’t try to dumb everything down so that a theoretical every-man can use the system. That’s a lofty aim, but seriously unlikely to succeed. I’m not talking about the admin and administration interface, I’m referring to the bits that let you actually build the site — the templates, styles etc.
Plenty of systems expect you to do ridiculous things like edit templates inside a web interface. Bah! I have a text editor for that. Just expose the templates to me in the file system and let me hack them as I need.
Themes? Utterly stupid. No serious CMS should have anything like themes. They increase the complexity of the implementation for little benefit. Having to hack a theming engine because it’s doing something stupid or is otherwise inflexible is annoying.
Basically, if we assume that a CMS and accompanying templates/styles will be set-up by people who understand how websites work, we don’t need to try and get clever with the implementation.
Extending the System Should Not Mean Using a Narrow API
If you use a CMS for a lot of client work you will have them ask for custom functionality. This is inevitable, so it’s vital that you are able to extend the CMS without going insane.
This comes in a number of forms:
- Plugins for common components — image galleries, forums etc
- Custom, site-specific code
- Over-riding default behaviour in the CMS itself
Most CMSs attempt to solve this by implementing a plugin API. Initially this seems simple enough, but it has some draw-backs. Generally you are limited to what the API gives you.
As for modifying the code in the CMS proper; OMG ARE YOU CRAZY? If you’re reduced to hacking the CMS into a custom version, you will lose your shit at some point in the future. Firstly, you need to maintain those changes — think you can remember the modifications you made in someone else’s code-base all those months ago? Secondly, upgrading is going to kick your arse, because you’ll need to remerge your hacks, then make sure they work.
Let’s Make Yet Another CMS
So that’s all basically an introduction and justification for making another CMS. As part of my work at Freerange Future we’ve been developing a new system. I know, I know, every web-shop seems to go out and make it’s own CMS, but honestly, this is gonna be worth it.
It’s built on top of Merb, MIT licensed and implemented as a merb-slice, meaning we can easily over-ride it’s behaviour and still upgrade it without going nuts. I also t plays nice with your own code.
Most importantly in my opinion, it doesn’t assume you’re an idiot. It won’t hold your hand, instead it assumes you know enough Ruby to be dangerous, but can be trusted not to take an eye out with it.
It’s called Gluttonberg and it lives in a repository on Github. The README and Wiki go into a little more detail about the implementation and features we plan to build, so if you’re curious, please have a look.
It’s obviously still a work in progress so if you’re interested in contributing please just message me on GitHub (lukesutton) and I’ll give you commit access to the main repo, no questions asked.
With the power of Gluttonberg, it’s my hope that we can power-slam the entire internet.
Dynamically Creating Classes
Here’s some interesting metaprogramming trix for generating classes at run-time. This is something I had to do recently, so I thought it would worthwhile writing them down — and yes I really did have a good reason for doing this, I swears.
So the first thing to note, is the the Class object actually has a #new method. This just creates a new class which you can then assign to a variable.
new_class = Class.new
A class isn’t so useful without methods, so you can pass a block to the new method which will act as the body for the class definition.
new_class = Class.new do
def cry!
"waaaagh!"
end
end
new_class.new.cry! #=> "waaaagh!"
It’s a regular class so you can do everything you usually would — subclass, instantiate, mix-in modules etc. Still, it’s not very nice having a class reference inside a regular variable, what you really want is to stick it in a constant. Seems easy enough, but remember we’re talking about doing this at run-time, so the code you’re calling will be inside a method. You cannot assign values to a constant inside a method. Oops. Luckily there is a way around it.
An evil little method called Object#const_set. So, if we define a class like this:
class NeedsToBeMoreDynamic
def self.make_a_class!
const_set("NeedsToBeMoreDynamic::KaPow", Class.new)
end
end
NeedsToBeMoreDynamic.make_a_class! #=> NeedsToBeMoreDynamic::KaPow
Right, that seems dead easy, but there is one caveat and it’s a big one, so be careful for $DEITY’s sake — #const_set will actually hijack an existing constant. That means if you’re not careful you’ll make things screwy. You can actually overwrite references to class definitions. That’s bad… obviously.
Don’t let that put you off though, this is definitely a handy technique to know.
Sass & Haml - A Sweet Romance Begins
If you’re just starting out using Sass, you can make things easier on yourself by having it automatically compile the stylesheets with every request. This tip applies to both Rails and Merb. Just add the following bit of code to your development.rb file.
Sass::Plugin.options[:always_update] = true
P.S. After being dubious for some time, I’ve now begun my romance with Haml and Sass. It’s sweet indeed. Terse, auto-formatting, variables. Oh my. Delicious.
More New Merb (0.5 is out now)
Just a quick heads-up. Merb has moved pretty quickly over the last few weeks, with lots of nice additions, code refactoring and general polish.
Now, Merb 0.5 is out. You can install it via RubyGems. Ezra has release notes on his blog.
Well done to all the devs! Merb just keeps looking better and better as it goes along. Yay!
I Don’t Like Ruby’s Class Variables
Just a general comment. The behaviour of class variables in Ruby is nonsensical.
I’ve had many frustrating moments dealing with the way class variables are handled in sub-classes — they’re shared between all subclasses, rather than belonging to just the one class — now I’m having fun trying to create them when I mix in a module.
What they do and how they are scoped is confusing. Definitely one of my least favourite parts of the language.
RubyGems - Get Your Backwards-compatibility Here
If you’ve upgraded to the latest version of RubyGems you might notice that some older gems break. This is because the #require_gem method is no longer deprecated, it’s been removed entirely. Instead we need to use the #gem method.
That’s cool, but in the meantime we still need #require_gem to work, since it may take awhile for all the various gems we rely on to be updated. Lucky for us it’s easy to do.
unless Object.respond_to? :require_gem
class Object
def require_gem(*args)
gem(*args)
end
end
end
Here we’re just adding the #require_gem method back to the Object class, which palms of it’s arguments to the new #gem method. To make sure it doesn’t break with older versions of RubyGems — an issue when working collaboratively — I’ve wrapped it in a test which checks to see if #require_gem is already declared, in which case we don’t have to add backwards-compatibility.
If you’re using Rails, you can put this bit of code in you environment.rb. Just make sure it comes before any requires for gems.
DataMapper - Introductory Docs
I finally got off my bum and put together some documentation for DataMapper. These are mainly introductory docs. Not exhaustive by any measure, but should help folks get up to speed. You can check them out here.
A Mullion Ways to Do the One Thing
As much as I like Ruby, sometimes I see a feature that just makes me ask why. WHY? Specifically, when you have two features that do exactly the same thing, why implement both? The best argument for redundant features is that one is a short cut for a common argument. The best examples are the various literals.
# Hash
{:yay => 'spasm', :hoon => 'town'}
# Array
[1, 2, 3, 4]
%w(array of four words)
# Integers and floats
1
1.2
# Strings
"Yes, this is actually a literal"
# Regular Expressions
/(\w+)\/|./
# Ranges
1..100
And more… There are loads of ‘em! Literals are one of the nice things about Ruby. They are also sadly, one of the worst. Why? Because many of them are redundant. One that I came across more recently made me quirk my brows:
# Create a hash
{1 => 2, 3 => 4} #=> {1 => 2, 3 => 4}
{1,2,3,4} #=> {1 => 2, 3 => 4}
The first is the most common literal for creating hashes. It’s perfect, since you’re listing the pairs that go into your new hash and you can see how the keys are related to the values. The second one is just a shorter version. More to the point, it’s a more opaque version. Why is it even there?
Just one more example:
# Create an array
%w(array of words) #=> ['array', 'of', 'words']
%w'array of words' #=> ['array', 'of', 'words']
%w{array of words} #=> ['array', 'of', 'words']
If you haven’t seen this literal before, it just takes a string and treats each separate word as an entry in the array — it’s equivalent to doing "array of words".split(' '). This means you can’t have multi-word entries, but it’s a super useful shortcut. The first is the most commonly used. The other two do the same thing, but use different characters to delineate the string.
It’s a tiny thing to be sure, but I really don’t like having all these different shortcuts to do the same thing. It’s inelegant. Sadly, new versions of Ruby will have more literals.
# Yet another hash literal
{key: 'value', pairs: 'augogo'} #=> {:key => 'value', :pairs => 'augogo'}
More deprecations in Ruby I say! Pick one good thing and stick with it.
But… I still love you Ruby *hugs*.
Rails - acts_as_tree Select Helper
Do you have a model with acts_as_tree? At some point you probably might want to generate a select with a representation of your tree — say categories and sub-categories for blog posts or something. I’ve seen some slightly nasty ways of doing this, so I thought I might try my hand at something cleaner.
Firstly, the most efficient way of building the options for the select is via recursion. Secondly, you shouldn’t try to do it with one method, otherwise you’ll end up checking conditions repeatedly — Is this the top level? Do I have to write out the select open or select close? — when you really don’t need to.
So I’ve split my helper into two methods. One to generate the select tag and another for the options. The method for the options recurses, going through each level in the hierarchy.
def select_for_tree(model, name, entries, options = {})
# Grab the current value of the specified attribute
current = instance_variable_get("@#{model}").send(name)
# Build the option tags
option_tags = options_for_tree(entries, current, 0)
# Check to see if we need to include a blank entry at the top
option_tags.insert(0, content_tag(:option)) if options[:include_blank]
# Build the select tag
select_tag("#{model}[#{name}]", option_tags, :id => "#{model}_#{name}")
end
def options_for_tree(entries, current, level)
options = ''
entries.each do |entry|
attrs = {:value => entry.id}
attrs[:selected] = 'selected' if entry.id == current
options < < content_tag(:option, ("- " * level) + entry.name, attrs)
# This is the bit that does the recursion.
options << options_for_tree(entry.children, current, level + 1) unless entry.children.empty?
end
options
end
Not particularly clever, but it was interesting trying to get something reasonably simple and clean.