More Obscure Features of Ruby
First go look at Nick Sieger's post about strange perlisms in ruby, cause it may be interesting for you. But talking about strange features in ruby, I believe there are some that may result even stranger, cause they are not even inherited from other languages, but are matz' own creation, I believe.
super on builtin methods
if you're redefining a builtin method you can use super to access the original one:
>> def puts(*args) >> super(*args) >> super(*args) >> end => nil >> puts 123 123 123
yet if you try with your own:
>> def foo() puts "foo" end
=> nil
>> def foo() super end
=> nil
>> foo
NoMethodError: super: no superclass method `foo'
from (irb):8:in `foo'
from (irb):10
super without arguments
I knew this feature for long, but never used it in real coding, even if I keep thinking it's handy. super, when used without arguments, passes all the arguments, so the above example would become:
>> def puts(a,b) >> super >> super >> end => nil >> puts 345, 567 345 567 345 567 => nil
The evil context-sensitive while and until modifiers:
Can you tell the difference between this two lines?
puts 'hello' while false begin puts 'hello' end while false
Well, the difference is that the latter will print "hello", because the while modifier always does at least one evaluation of the expression when preceded by a begin..end block. The same happens with the until modifier. Luckily, this evil behaviour is supposed to disappear.
do something, handle exceptions.. or else?
Did you know that ruby's begin allows the definition of an else clause? The else clause is actually part of the rescue part of the block,. and is executed whenever an exception is not raised:
>> def check(x) >> begin ?> raise if x==2 >> rescue >> "error" >> else ?> "ok" >> end >> end => nil >> check(1) => "ok" >> check(2) => "error"
..and of course, you do not need begin..
because, I believe you know this, you can write:
>> def check(x) >> raise if x==2 >> rescue >> "error" >> else ?> "ok" >> end => nil >> check(1) => "ok" >> check(2) => "error"
methods with whitespace, yay!
I find this quite useful, actually. If you define a method bypassing the ruby parser with define_method you can give it any name you want.
>> class K
>> define_method("method: hard to get") { 'got!' }
>> end
=> #
>> K.new.send 'method: hard to get'
=> "got!"
You won't be able to call the method with normal ruby syntax, which makes it less or more useful depending on your problem space.
And finally, there is a whole slant of strange things that I believe are remnants of matz' experimenting with the language (is alias $global $other_global used somewhere outside of english.rb?), and even if some of them are quite frightening (if /regex/ anyone?) they will be phased out, so it's ok. If I recall correct ruby also had a glob operator ( <*.c> ) that was killed in the early days, so I trust matz to fix the oddities of the language sooner or later :)
See all commentsMy Tiny DocTest for ruby
I believe that doctest for python is one of the best test libraries available, because it pushes the cost to develop functional tests to zero.
While I’m writing a dummy object persistence layer I thought it would have been nice to have something like that, basically seeking some kind of literate testing process.
This is the first attempt at it (warning dirty, slow, duplicated code).
It somehow works, can be run from rcov/rake/ruby, loaded with multiple files, and allows writing nice tests like this one . As you can see in the code, everything that does not look like irb code is ignored, which allows adding comments, leave python code mixed with ruby, write formulas and so on.
The lib is really half-backed, for example you canì’t use multiline declarations in irb or print something to screen, but I think it is a nice small thing.
You can find a different take on sample/doc testing in manveru’s repository
See all commentsRails vs Django: a non biased yet useless comparison
Lately I've been making my hands a little bit dirty with django, and since I already did a little bit of Rails I think I'm entitled to do a small comparison. No, this is a lie. I'm entitled to do that because I have a blog and that's it.
The non biased assertion is due to the fact that I like both frameworks and I do love both languages, the useless one is well, because you will still have to evaluate the things by yourself , cause I am not an expert at either and I think that my few readers are smart enough to understand that choosing an infrastructure requires more work than reading a random blog entry.
Both frameworks use the new classic MVC pattern (even if in django's lingo it's called MTV you will notice that it is 99.9% the same), and both framework provide some othe features, so I'll just split the comparison by these concepts.
* Model * The model layer in django and rails is basically built out of classes that map to DB tables, but the things are slightly different.
The model in rails is comprised of two things: an SQL definition and a Ruby definition. Yes I know about Dr Nic's magic models. You can also create the database in pure ruby by using the wonderful migrations' system that rails provides, but the model is still built out of the pair DB structure + Ruby code. AFAIK django doesn't have yet something on the level of Rails migrations, that allows you to programmatically move back and forth in time easily.
Django uses a single definition in python with more metadata, and provides some useful python datatypes that are mapped transparently on the DBMS, so that a Post class can have a SlugField, while a Comment can have EmailField and IPAddressField. Yet, you can still go down to the SQL level if you want.
It seem to me that the support for validation is quite similar under the surface for both frameworks: you can validate single fields ot whole objects at different times and stack different validators.
One big flaw in current django's models is that they don't allow inheritance, and so if you have a lot of models that differ just slightly you can't save work using this approach. Rails' ActiveRecord gets a big plus for this, but this should be solved soon in django.
* "the thing that does *which" ** Rails calls the module that chooses which data to show the Controller. For some reason Django calls it the View whereas the Controller is the underlying support software.
Rails which is made of two elements: Controller objects and actions.
A request for a page is processed so that it instantiates a Controller object and setups variables appropriately, then the action method is called.
At the class level you can define behaviour shared between the various action with a nice syntax, but I don't particularly love the :except and :only things.
In django an action is just a function which takes a fixed argument, the request, and an optional set of named arguments. I love the way named arguments work in python and I think that this approach provides much more readability, but to have that in ruby we will have to wait for ruby 2.0 (or use evil.rb which doesn't feel enterprisey).
The only thing I dislike in django's view is that you have to explicitly point out to a template file when rendering a view, whereas rails' convention over configuration in this case relieves the user of a repetitive and non-interesting operation.
I also think that not having the class Foo < Controller boilerplate is better, but the bad news is that django doesn't do magic requiring of modules and you have to do it yourself, so everything balance out.
Both systems allow caching but (for what I understood) Django mostly uses time-based cache invalidation, while rails provides only an event-based expiring behaviour.
Anyway there are plugins for rails that allow time based invalidation, and I believe that it should be possible to expire something in an event-based fashion in django too, cause the underlying mechanics are the same (CACHE.set(key,val), CACHE.get(key) and CACHE.del(key)).
It seems that django doesn't provide the fine-grained caching control that rails has, allowing just a whole-page caching or forcing the user to resort to the low level cache api, which I think is a bad thing.
Finally, django uses exceptions to handle error codes, which I believe is a far better solution than rails :status=>code, because it allows breaking out of an action from an utility method.
This allows, the refactoring control in utility methods, having shortcuts such as get_object_or_404(Class,key=val), which simplify the writing of views.
* "the thing that does _how_" * The actual showing of data is usually done in both frameworks through templates, which rails call Views. Django uses an interestint template language while rails uses ruby embedded in XHTML by deafult, but different templating engines can be used as plugins very easily.
Both allow the composition of smaller units to enhance reuse and ease of maintenance and it I believe that apart from personal preferences there are not big differences in this area.
* Other things * I think that the main differences in rails and django can be appreciated going away from the basic elements and looking at the rest of the platform, where the frameworks differ greatly.
First, django provides internationalization as a builtin concept while in django you're forced to use external libraries such as Globalize. Sadly, I am convinced that this is such an important feature that it must be builtin and it is an error not to have it, because to do it right the framework must be engineered around it. It must be also noticed that python's support for unicode (and other text encodings) in general is far more advanced than ruby's, which basically just kind-of-supports utf-8 (wait for ruby2, again).
Second, django's automatic generation of an administration facility, complete with authorization support and a bunch of space for customization is amazing. Again, there are modules for rails that provide this kind of behaviour, but having such a feature builtin makes it a foundation and a reference against which every programmer can code, which makes coee sharing easier.
In general django has builtin support for a lot of functionalities that are common in modern web apps, not only admin and auth, but also sitemaps, syndication, comments and much more.
Rails takes a minimalistic approach on this and pushes all this stuff in plugins. The rails community is producing plugins at an incredible rate, and even if not all of them are compatible and high quality code there is a lot of choice.
In the old days rails' plugins used to have some issues and this was the reason for the existence of things like rails engines but as of 1.2 this problems are not there anymore, Django allows code sharing through the integration of different apps which is what the admin above mentioned features are, and each of this add-on can contain something as easy as a textilize() function to a whole application such as a wiki or a blog.
There are not so much django apps as there are rails plugins, and I believe that this depends on 3 factors
- smaller community
- slightly harder sharing (in rails you just user
script/plugin installand you're done) - less duplication
The latter is hardly dependent on django coming with more batteries included, so for example you don't need a plugin for creating slugs because there is a lready a
slugify()function.
* Conclusion * I wish rails had more batteries included, and that ruby was a little bit more like python (i.e. modules, named args, function decorator syntax). And I wish django used more conventions/less typing, and python was more like ruby (blocks, functions call without parenthesis, implicit self). but I still like both, pick your choice or even better try both. This at least will make you ready to write your own framework ;)
See all commentsGoogle Summer of Code: Ex-Post thoughts
Ok, google’s SoC is ended, and I had some spare time to repair this blog which was broken for a while, so now you’re getting some random thoughts on it and on my work.
If you ever plan to try it in the next years you may find this useful, possibly.
Lessons Learned
- get a timeline, set milestones of what you should have done in a week or so, this prevents the bad feeling of not knowing how much you should do tomorrow and the fear of not having a chance to get stuff done in time.
- write tests, and really check that they are working, I lost a lot of time because I was testing against old installed rubygems instead of my work. Life just sucks, sometimes.
- if the main repository is unstable go away, in the first part of my SoC I tried to work with the main repository, which was under heavy refactoring. This meant that basic functionalities got broken and thus I should go around them. Try to find a stable repository, if you have good tests you should be able to port your code to the main code base (quite) easily once it gets stable again.
- stay in touch with other devs, the idea of SoC is to be part of a community, and that is always the best way to find help, answers, and moral support. I owe a beer to everyone in #nitro, possibly.
- KISS & YAGNI, ok, it should be obvious to anyone that these acronyms are important, but well, it is hard to really respect the principles.
- find a good mentor, mine was nice (fining out we both coose to learn AliceML this year was incredible :) but I’ve heard quite a bit of people that lost contact with her/him, and that made developing much harder.
- put out your code soon, set up a personal repository if you don’t want/can mess up with the main one, it makes easy for people/friends/mentors to review your code and get early warnings about it. Being shy about your code is a bad habit. Possibly this extends out into real life.
- get a good development platform, take time to setup it properly, and do investigate small problems about it ASAP, I lost a lot of time due to subtle differences in the DBMS backends for Og because some are unstable due to recent rewrite.
- make small steps, “writing a ui” is an extremely hard thing, “wrap errors in a div” is a 5 minute thing. If you use darcs try record‘ing after each small step.
- facets rocks, search stuff in it before you reinvent the wheel.
- never ever hide errors, if the framework does, change its behaviour as long as you work on it, you can make it safe (or utterly broken, depending on your point of view) again later. If I ever see “rescue Object” again I could start crying. (Luckily those are being completely removed).
- get some demo from the start, the Django tutorial was a great source to start hacking towards a meaningful objective for an admin ui, for example. This allows discovering corners that you may have not thought of in the beginning.
- avoid distractions, and I do not mean real life or eventual Anime video, I mean getting deep into solving completely off-topic issues just because they incidentally relate to some remote part of your work. Having an Array like [1,2,3,5] somewhere in your code does not mean you must rewrite the Prime class and investigate the Riemann Hypothesis.
Results wrt original Plan
- new gen infrastructure [ok]
- gen scaffolding [ok]
- gen administration [ok]
- proto code simplification [ok]
- order and choice of shown fields [ok]
- order and choice of shown classes [ok]
- input methods for complex fields [ko, only relations, need new control system for stuff like tags]
- choice of navigational UI [ok, easily reusable/hackable breadcrumbs & menu helpers]
- AJAXish stuff [ko, needs more work]
- per-part settings [ok]
- various scaffolding settings [ok]
- online configuration [ok]
Various added stuff
- tests
- automagic methods allows usage of default
to_s,to_hrefandto_edit_hrefwith Og managed objects. - helper to build a table of objects
- helper to show a single object in table view
- helper to show errors in meaningful xhtml
- NavigationHelper
- gen/part allows easy importing of an existing part into a new project
- automagic search key allows searching objects through an attribute by setting a single setting
- yaml export of the dbms
- customizable table links (could have more settings for tables though)
- proto split
- SystemPage element allows easy hacking of the admin view
- stylesheet (please do help, I’m very bad at css design)
- attribute_to_html
- visual feedback on successfull creation and errors with better handling of errors (i.e. data are kept in the form)
- some og and nitro fixes
- merged 30+ patch from devlab repository into main one, plus conflict handling
- some ui reworking, new view.xhtml, search.xhtml, admin/index and other.
- the great two-line header :)
Conclusions
This was uber cool, I wish I had more time back in july, but well, my last exam was something like 27 of that month. Obviously I plan to keep work on the administration part, the code needs more refactoring and I’m thinking of at least three new settings (multiple-attribute search key a-la streamlined, non-tabular view for objects and breadcrumbish title helper), plus I need more tests.
If you want to take a peek at what I’ve don you can look at the temporary video available here , which shows a part of the available features. Please do not consider this a permanent link, I could remove it as soon as I have another video showing more stuff.
Thanks
To google for organizing the Summer of Code, to RubyCentral for choosing me, to Bryan for being my mentor, to George for Nitro and Tom for facets, to everyone in #nitro, #ruby-it, #ruby-lang and #verbamanent for uncountable help and fun.
See all comments